mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
refactor(docker/containers): migrate commands tab to react [EE-5208] (#10085)
This commit is contained in:
parent
46e73ee524
commit
f7366d9788
42 changed files with 1783 additions and 951 deletions
|
@ -1,5 +1,4 @@
|
|||
import _ from 'lodash-es';
|
||||
import splitargs from 'splitargs/src/splitargs';
|
||||
|
||||
const portPattern = /^([1-9]|[1-5]?[0-9]{2,4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/m;
|
||||
|
||||
|
@ -65,18 +64,6 @@ angular.module('portainer.docker').factory('ContainerHelper', [
|
|||
'use strict';
|
||||
var helper = {};
|
||||
|
||||
helper.commandStringToArray = function (command) {
|
||||
return splitargs(command);
|
||||
};
|
||||
|
||||
helper.commandArrayToString = function (array) {
|
||||
return array
|
||||
.map(function (elem) {
|
||||
return "'" + elem + "'";
|
||||
})
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
helper.configFromContainer = function (container) {
|
||||
var config = container.Config;
|
||||
// HostConfig
|
||||
|
|
9
app/docker/helpers/containers.ts
Normal file
9
app/docker/helpers/containers.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { splitargs } from './splitargs';
|
||||
|
||||
export function commandStringToArray(command: string) {
|
||||
return splitargs(command);
|
||||
}
|
||||
|
||||
export function commandArrayToString(array: string[]) {
|
||||
return array.map((elem) => `'${elem}'`).join(' ');
|
||||
}
|
68
app/docker/helpers/splitargs.test.ts
Normal file
68
app/docker/helpers/splitargs.test.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Created by elgs on 7/2/14.
|
||||
*/
|
||||
|
||||
import { splitargs } from './splitargs';
|
||||
|
||||
describe('splitargs Suite', () => {
|
||||
beforeEach(() => {});
|
||||
afterEach(() => {});
|
||||
|
||||
it('should split double quoted string', () => {
|
||||
const i = " I said 'I am sorry.', and he said \"it doesn't matter.\" ";
|
||||
const o = splitargs(i);
|
||||
expect(7).toBe(o.length);
|
||||
expect(o[0]).toBe('I');
|
||||
expect(o[1]).toBe('said');
|
||||
expect(o[2]).toBe('I am sorry.,');
|
||||
expect(o[3]).toBe('and');
|
||||
expect(o[4]).toBe('he');
|
||||
expect(o[5]).toBe('said');
|
||||
expect(o[6]).toBe("it doesn't matter.");
|
||||
});
|
||||
|
||||
it('should split pure double quoted string', () => {
|
||||
const i = 'I said "I am sorry.", and he said "it doesn\'t matter."';
|
||||
const o = splitargs(i);
|
||||
expect(o).toHaveLength(7);
|
||||
expect(o[0]).toBe('I');
|
||||
expect(o[1]).toBe('said');
|
||||
expect(o[2]).toBe('I am sorry.,');
|
||||
expect(o[3]).toBe('and');
|
||||
expect(o[4]).toBe('he');
|
||||
expect(o[5]).toBe('said');
|
||||
expect(o[6]).toBe("it doesn't matter.");
|
||||
});
|
||||
|
||||
it('should split single quoted string', () => {
|
||||
const i = 'I said "I am sorry.", and he said "it doesn\'t matter."';
|
||||
const o = splitargs(i);
|
||||
expect(o).toHaveLength(7);
|
||||
expect(o[0]).toBe('I');
|
||||
expect(o[1]).toBe('said');
|
||||
expect(o[2]).toBe('I am sorry.,');
|
||||
expect(o[3]).toBe('and');
|
||||
expect(o[4]).toBe('he');
|
||||
expect(o[5]).toBe('said');
|
||||
expect(o[6]).toBe("it doesn't matter.");
|
||||
});
|
||||
|
||||
it('should split pure single quoted string', () => {
|
||||
const i = "I said 'I am sorry.', and he said \"it doesn't matter.\"";
|
||||
const o = splitargs(i);
|
||||
expect(o).toHaveLength(7);
|
||||
expect(o[0]).toBe('I');
|
||||
expect(o[1]).toBe('said');
|
||||
expect(o[2]).toBe('I am sorry.,');
|
||||
expect(o[3]).toBe('and');
|
||||
expect(o[4]).toBe('he');
|
||||
expect(o[5]).toBe('said');
|
||||
expect(o[6]).toBe("it doesn't matter.");
|
||||
});
|
||||
|
||||
it('should split to 4 empty strings', () => {
|
||||
const i = ',,,';
|
||||
const o = splitargs(i, ',', true);
|
||||
expect(o).toHaveLength(4);
|
||||
});
|
||||
});
|
114
app/docker/helpers/splitargs.ts
Normal file
114
app/docker/helpers/splitargs.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
|
||||
Splits strings into tokens by given separator except treating quoted part as a single token.
|
||||
|
||||
|
||||
#Usage
|
||||
```javascript
|
||||
var splitargs = require('splitargs');
|
||||
|
||||
var i1 = "I said 'I am sorry.', and he said \"it doesn't matter.\"";
|
||||
var o1 = splitargs(i1);
|
||||
console.log(o1);
|
||||
|
||||
[ 'I',
|
||||
'said',
|
||||
'I am sorry.,',
|
||||
'and',
|
||||
'he',
|
||||
'said',
|
||||
'it doesn\'t matter.' ]
|
||||
|
||||
|
||||
var i2 = "I said \"I am sorry.\", and he said \"it doesn't matter.\"";
|
||||
var o2 = splitargs(i2);
|
||||
console.log(o2);
|
||||
|
||||
[ 'I',
|
||||
'said',
|
||||
'I am sorry.,',
|
||||
'and',
|
||||
'he',
|
||||
'said',
|
||||
'it doesn\'t matter.' ]
|
||||
|
||||
|
||||
var i3 = 'I said "I am sorry.", and he said "it doesn\'t matter."';
|
||||
var o3 = splitargs(i3);
|
||||
console.log(o3);
|
||||
|
||||
[ 'I',
|
||||
'said',
|
||||
'I am sorry.,',
|
||||
'and',
|
||||
'he',
|
||||
'said',
|
||||
'it doesn\'t matter.' ]
|
||||
|
||||
|
||||
var i4 = 'I said \'I am sorry.\', and he said "it doesn\'t matter."';
|
||||
var o4 = splitargs(i4);
|
||||
console.log(o4);
|
||||
|
||||
[ 'I',
|
||||
'said',
|
||||
'I am sorry.,',
|
||||
'and',
|
||||
'he',
|
||||
'said',
|
||||
'it doesn\'t matter.' ]
|
||||
```
|
||||
*/
|
||||
|
||||
export function splitargs(
|
||||
input: string,
|
||||
sep?: RegExp | string,
|
||||
keepQuotes = false
|
||||
) {
|
||||
const separator = sep || /\s/g;
|
||||
let singleQuoteOpen = false;
|
||||
let doubleQuoteOpen = false;
|
||||
let tokenBuffer = [];
|
||||
const ret = [];
|
||||
|
||||
const arr = input.split('');
|
||||
for (let i = 0; i < arr.length; ++i) {
|
||||
const element = arr[i];
|
||||
const matches = element.match(separator);
|
||||
// TODO rewrite without continue
|
||||
/* eslint-disable no-continue */
|
||||
if (element === "'" && !doubleQuoteOpen) {
|
||||
if (keepQuotes) {
|
||||
tokenBuffer.push(element);
|
||||
}
|
||||
singleQuoteOpen = !singleQuoteOpen;
|
||||
continue;
|
||||
} else if (element === '"' && !singleQuoteOpen) {
|
||||
if (keepQuotes) {
|
||||
tokenBuffer.push(element);
|
||||
}
|
||||
doubleQuoteOpen = !doubleQuoteOpen;
|
||||
continue;
|
||||
}
|
||||
/* eslint-enable no-continue */
|
||||
|
||||
if (!singleQuoteOpen && !doubleQuoteOpen && matches) {
|
||||
if (tokenBuffer.length > 0) {
|
||||
ret.push(tokenBuffer.join(''));
|
||||
tokenBuffer = [];
|
||||
} else if (sep) {
|
||||
ret.push(element);
|
||||
}
|
||||
} else {
|
||||
tokenBuffer.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenBuffer.length > 0) {
|
||||
ret.push(tokenBuffer.join(''));
|
||||
} else if (sep) {
|
||||
ret.push('');
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
26
app/docker/react/components/containers.ts
Normal file
26
app/docker/react/components/containers.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import angular from 'angular';
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||
import {
|
||||
CommandsTab,
|
||||
CommandsTabValues,
|
||||
commandsTabValidation,
|
||||
} from '@/react/docker/containers/CreateView/CommandsTab';
|
||||
|
||||
const ngModule = angular.module(
|
||||
'portainer.docker.react.components.containers',
|
||||
[]
|
||||
);
|
||||
|
||||
export const containersModule = ngModule.name;
|
||||
|
||||
withFormValidation<ComponentProps<typeof CommandsTab>, CommandsTabValues>(
|
||||
ngModule,
|
||||
withUIRouter(withReactQuery(CommandsTab)),
|
||||
'dockerCreateContainerCommandsTab',
|
||||
['apiVersion'],
|
||||
commandsTabValidation
|
||||
);
|
|
@ -22,8 +22,10 @@ import { AgentHostBrowser } from '@/react/docker/host/BrowseView/AgentHostBrowse
|
|||
import { AgentVolumeBrowser } from '@/react/docker/volumes/BrowseView/AgentVolumeBrowser';
|
||||
import { ProcessesDatatable } from '@/react/docker/containers/StatsView/ProcessesDatatable';
|
||||
|
||||
import { containersModule } from './containers';
|
||||
|
||||
const ngModule = angular
|
||||
.module('portainer.docker.react.components', [])
|
||||
.module('portainer.docker.react.components', [containersModule])
|
||||
.component('dockerfileDetails', r2a(DockerfileDetails, ['image']))
|
||||
.component('dockerHealthStatus', r2a(HealthStatus, ['health']))
|
||||
.component(
|
||||
|
|
|
@ -8,7 +8,7 @@ import { withReactQuery } from '@/react-tools/withReactQuery';
|
|||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
export const containersModule = angular
|
||||
.module('portainer.docker.containers', [])
|
||||
.module('portainer.docker.react.views.containers', [])
|
||||
.component(
|
||||
'containersView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ListView))), ['endpoint'])
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
import { useQuery } from 'react-query';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import axios, { parseAxiosError } from '@/portainer/services/axios';
|
||||
|
||||
export interface VersionResponse {
|
||||
ApiVersion: string;
|
||||
}
|
||||
|
||||
export async function getVersion(environmentId: EnvironmentId) {
|
||||
try {
|
||||
const { data } = await axios.get<VersionResponse>(
|
||||
buildUrl(environmentId, 'version')
|
||||
);
|
||||
return data;
|
||||
} catch (err) {
|
||||
throw parseAxiosError(err as Error, 'Unable to retrieve version');
|
||||
}
|
||||
}
|
||||
|
||||
export interface InfoResponse {
|
||||
Swarm?: {
|
||||
NodeID: string;
|
||||
ControlAvailable: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export async function getInfo(environmentId: EnvironmentId) {
|
||||
try {
|
||||
const { data } = await axios.get<InfoResponse>(
|
||||
buildUrl(environmentId, 'info')
|
||||
);
|
||||
return data;
|
||||
} catch (err) {
|
||||
throw parseAxiosError(err as Error, 'Unable to retrieve version');
|
||||
}
|
||||
}
|
||||
|
||||
export function useInfo<TSelect = InfoResponse>(
|
||||
environmentId: EnvironmentId,
|
||||
select?: (info: InfoResponse) => TSelect
|
||||
) {
|
||||
return useQuery(
|
||||
['environment', environmentId, 'docker', 'info'],
|
||||
() => getInfo(environmentId),
|
||||
{
|
||||
select,
|
||||
}
|
||||
);
|
||||
}
|
||||
export function useVersion<TSelect = VersionResponse>(
|
||||
environmentId: EnvironmentId,
|
||||
select?: (info: VersionResponse) => TSelect
|
||||
) {
|
||||
return useQuery(
|
||||
['environment', environmentId, 'docker', 'version'],
|
||||
() => getVersion(environmentId),
|
||||
{
|
||||
select,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function buildUrl(
|
||||
environmentId: EnvironmentId,
|
||||
action: string,
|
||||
subAction = ''
|
||||
) {
|
||||
let url = `/endpoints/${environmentId}/docker/${action}`;
|
||||
|
||||
if (subAction) {
|
||||
url += `/${subAction}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { Terminal } from 'xterm';
|
||||
import { baseHref } from '@/portainer/helpers/pathHelper';
|
||||
import { commandStringToArray } from '@/docker/helpers/containers';
|
||||
|
||||
angular.module('portainer.docker').controller('ContainerConsoleController', [
|
||||
'$scope',
|
||||
|
@ -101,7 +102,7 @@ angular.module('portainer.docker').controller('ContainerConsoleController', [
|
|||
AttachStderr: true,
|
||||
Tty: true,
|
||||
User: $scope.formValues.user,
|
||||
Cmd: ContainerHelper.commandStringToArray(command),
|
||||
Cmd: commandStringToArray(command),
|
||||
};
|
||||
|
||||
ContainerService.createExec(execConfig)
|
||||
|
|
|
@ -7,9 +7,10 @@ import { confirmDestructive } from '@@/modals/confirm';
|
|||
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||
import { buildConfirmButton } from '@@/modals/utils';
|
||||
|
||||
import { ContainerCapabilities, ContainerCapability } from '../../../models/containerCapabilities';
|
||||
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel';
|
||||
import { ContainerDetailsViewModel } from '../../../models/container';
|
||||
import { commandsTabUtils } from '@/react/docker/containers/CreateView/CommandsTab';
|
||||
import { ContainerCapabilities, ContainerCapability } from '@/docker/models/containerCapabilities';
|
||||
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
||||
import { ContainerDetailsViewModel } from '@/docker/models/container';
|
||||
|
||||
import './createcontainer.css';
|
||||
|
||||
|
@ -20,11 +21,9 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
'$state',
|
||||
'$timeout',
|
||||
'$transition$',
|
||||
'$filter',
|
||||
'$analytics',
|
||||
'Container',
|
||||
'ContainerHelper',
|
||||
'Image',
|
||||
'ImageHelper',
|
||||
'Volume',
|
||||
'NetworkService',
|
||||
|
@ -37,7 +36,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
'RegistryService',
|
||||
'SystemService',
|
||||
'SettingsService',
|
||||
'PluginService',
|
||||
'HttpRequestHelper',
|
||||
'endpoint',
|
||||
function (
|
||||
|
@ -47,11 +45,9 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$state,
|
||||
$timeout,
|
||||
$transition$,
|
||||
$filter,
|
||||
$analytics,
|
||||
Container,
|
||||
ContainerHelper,
|
||||
Image,
|
||||
ImageHelper,
|
||||
Volume,
|
||||
NetworkService,
|
||||
|
@ -64,7 +60,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
RegistryService,
|
||||
SystemService,
|
||||
SettingsService,
|
||||
PluginService,
|
||||
HttpRequestHelper,
|
||||
endpoint
|
||||
) {
|
||||
|
@ -80,7 +75,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
selectedGPUs: ['all'],
|
||||
capabilities: ['compute', 'utility'],
|
||||
},
|
||||
Console: 'none',
|
||||
Volumes: [],
|
||||
NetworkContainer: null,
|
||||
Labels: [],
|
||||
|
@ -95,15 +89,12 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
MemoryLimit: 0,
|
||||
MemoryReservation: 0,
|
||||
ShmSize: 64,
|
||||
CmdMode: 'default',
|
||||
EntrypointMode: 'default',
|
||||
Env: [],
|
||||
NodeName: null,
|
||||
capabilities: [],
|
||||
Sysctls: [],
|
||||
LogDriverName: '',
|
||||
LogDriverOpts: [],
|
||||
RegistryModel: new PorImageRegistryModel(),
|
||||
commands: commandsTabUtils.getDefaultViewModel(),
|
||||
};
|
||||
|
||||
$scope.extraNetworks = {};
|
||||
|
@ -114,6 +105,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
mode: '',
|
||||
pullImageValidity: true,
|
||||
settingUnlimitedResources: false,
|
||||
containerIsLoaded: false,
|
||||
};
|
||||
|
||||
$scope.onAlwaysPullChange = onAlwaysPullChange;
|
||||
|
@ -121,6 +113,13 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$scope.handleAutoRemoveChange = handleAutoRemoveChange;
|
||||
$scope.handlePrivilegedChange = handlePrivilegedChange;
|
||||
$scope.handleInitChange = handleInitChange;
|
||||
$scope.handleCommandsChange = handleCommandsChange;
|
||||
|
||||
function handleCommandsChange(commands) {
|
||||
return $scope.$evalAsync(() => {
|
||||
$scope.formValues.commands = commands;
|
||||
});
|
||||
}
|
||||
|
||||
function onAlwaysPullChange(checked) {
|
||||
return $scope.$evalAsync(() => {
|
||||
|
@ -179,10 +178,12 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$scope.config = {
|
||||
Image: '',
|
||||
Env: [],
|
||||
Cmd: '',
|
||||
Cmd: null,
|
||||
MacAddress: '',
|
||||
ExposedPorts: {},
|
||||
Entrypoint: '',
|
||||
Entrypoint: null,
|
||||
WorkingDir: '',
|
||||
User: '',
|
||||
HostConfig: {
|
||||
RestartPolicy: {
|
||||
Name: 'no',
|
||||
|
@ -201,6 +202,10 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
CapAdd: [],
|
||||
CapDrop: [],
|
||||
Sysctls: {},
|
||||
LogConfig: {
|
||||
Type: '',
|
||||
Config: {},
|
||||
},
|
||||
},
|
||||
NetworkingConfig: {
|
||||
EndpointsConfig: {},
|
||||
|
@ -262,14 +267,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$scope.formValues.Sysctls.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.addLogDriverOpt = function () {
|
||||
$scope.formValues.LogDriverOpts.push({ name: '', value: '' });
|
||||
};
|
||||
|
||||
$scope.removeLogDriverOpt = function (index) {
|
||||
$scope.formValues.LogDriverOpts.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.fromContainerMultipleNetworks = false;
|
||||
|
||||
function prepareImageConfig(config) {
|
||||
|
@ -284,36 +281,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
config.HostConfig.PortBindings = bindings;
|
||||
}
|
||||
|
||||
function prepareConsole(config) {
|
||||
var value = $scope.formValues.Console;
|
||||
var openStdin = true;
|
||||
var tty = true;
|
||||
if (value === 'tty') {
|
||||
openStdin = false;
|
||||
} else if (value === 'interactive') {
|
||||
tty = false;
|
||||
} else if (value === 'none') {
|
||||
openStdin = false;
|
||||
tty = false;
|
||||
}
|
||||
config.OpenStdin = openStdin;
|
||||
config.Tty = tty;
|
||||
}
|
||||
|
||||
function prepareCmd(config) {
|
||||
if (_.isEmpty(config.Cmd) || $scope.formValues.CmdMode == 'default') {
|
||||
delete config.Cmd;
|
||||
} else {
|
||||
config.Cmd = ContainerHelper.commandStringToArray(config.Cmd);
|
||||
}
|
||||
}
|
||||
|
||||
function prepareEntrypoint(config) {
|
||||
if ($scope.formValues.EntrypointMode == 'default' || (_.isEmpty(config.Cmd) && _.isEmpty(config.Entrypoint))) {
|
||||
config.Entrypoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
function prepareEnvironmentVariables(config) {
|
||||
config.Env = envVarsUtils.convertToArrayOfStrings($scope.formValues.Env);
|
||||
}
|
||||
|
@ -447,23 +414,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
}
|
||||
}
|
||||
|
||||
function prepareLogDriver(config) {
|
||||
var logOpts = {};
|
||||
if ($scope.formValues.LogDriverName) {
|
||||
config.HostConfig.LogConfig = { Type: $scope.formValues.LogDriverName };
|
||||
if ($scope.formValues.LogDriverName !== 'none') {
|
||||
$scope.formValues.LogDriverOpts.forEach(function (opt) {
|
||||
if (opt.name) {
|
||||
logOpts[opt.name] = opt.value;
|
||||
}
|
||||
});
|
||||
if (Object.keys(logOpts).length !== 0 && logOpts.constructor === Object) {
|
||||
config.HostConfig.LogConfig.Config = logOpts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function prepareCapabilities(config) {
|
||||
var allowed = $scope.formValues.capabilities.filter(function (item) {
|
||||
return item.allowed === true;
|
||||
|
@ -511,40 +461,22 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
|
||||
function prepareConfiguration() {
|
||||
var config = angular.copy($scope.config);
|
||||
prepareCmd(config);
|
||||
prepareEntrypoint(config);
|
||||
config = commandsTabUtils.toRequest(config, $scope.formValues.commands);
|
||||
|
||||
prepareNetworkConfig(config);
|
||||
prepareImageConfig(config);
|
||||
preparePortBindings(config);
|
||||
prepareConsole(config);
|
||||
prepareEnvironmentVariables(config);
|
||||
prepareVolumes(config);
|
||||
prepareLabels(config);
|
||||
prepareDevices(config);
|
||||
prepareResources(config);
|
||||
prepareLogDriver(config);
|
||||
prepareCapabilities(config);
|
||||
prepareSysctls(config);
|
||||
prepareGPUOptions(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
function loadFromContainerCmd() {
|
||||
if ($scope.config.Cmd) {
|
||||
$scope.config.Cmd = ContainerHelper.commandArrayToString($scope.config.Cmd);
|
||||
$scope.formValues.CmdMode = 'override';
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromContainerEntrypoint() {
|
||||
if (_.has($scope.config, 'Entrypoint')) {
|
||||
if ($scope.config.Entrypoint == null) {
|
||||
$scope.config.Entrypoint = '';
|
||||
}
|
||||
$scope.formValues.EntrypointMode = 'override';
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromContainerPortBindings() {
|
||||
const bindings = ContainerHelper.sortAndCombinePorts($scope.config.HostConfig.PortBindings);
|
||||
$scope.config.HostConfig.PortBindings = bindings;
|
||||
|
@ -641,18 +573,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
}
|
||||
}
|
||||
|
||||
function loadFromContainerConsole() {
|
||||
if ($scope.config.OpenStdin && $scope.config.Tty) {
|
||||
$scope.formValues.Console = 'both';
|
||||
} else if (!$scope.config.OpenStdin && $scope.config.Tty) {
|
||||
$scope.formValues.Console = 'tty';
|
||||
} else if ($scope.config.OpenStdin && !$scope.config.Tty) {
|
||||
$scope.formValues.Console = 'interactive';
|
||||
} else if (!$scope.config.OpenStdin && !$scope.config.Tty) {
|
||||
$scope.formValues.Console = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadFromContainerDevices() {
|
||||
var path = [];
|
||||
for (var dev in $scope.config.HostConfig.Devices) {
|
||||
|
@ -765,15 +685,14 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$scope.fromContainer = fromContainer;
|
||||
$scope.state.mode = 'duplicate';
|
||||
$scope.config = ContainerHelper.configFromContainer(fromContainer.Model);
|
||||
loadFromContainerCmd(d);
|
||||
loadFromContainerEntrypoint(d);
|
||||
loadFromContainerLogging(d);
|
||||
|
||||
$scope.formValues.commands = commandsTabUtils.toViewModel(d);
|
||||
|
||||
loadFromContainerPortBindings(d);
|
||||
loadFromContainerVolumes(d);
|
||||
loadFromContainerNetworkConfig(d);
|
||||
loadFromContainerEnvironmentVariables(d);
|
||||
loadFromContainerLabels(d);
|
||||
loadFromContainerConsole(d);
|
||||
loadFromContainerDevices(d);
|
||||
loadFromContainerDeviceRequests(d);
|
||||
loadFromContainerImageConfig(d);
|
||||
|
@ -781,22 +700,14 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
loadFromContainerCapabilities(d);
|
||||
loadFromContainerSysctls(d);
|
||||
})
|
||||
.then(() => {
|
||||
$scope.state.containerIsLoaded = true;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve container');
|
||||
});
|
||||
}
|
||||
|
||||
function loadFromContainerLogging(config) {
|
||||
var logConfig = config.HostConfig.LogConfig;
|
||||
$scope.formValues.LogDriverName = logConfig.Type;
|
||||
$scope.formValues.LogDriverOpts = _.map(logConfig.Config, function (value, name) {
|
||||
return {
|
||||
name: name,
|
||||
value: value,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function initView() {
|
||||
var nodeName = $transition$.params().nodeName;
|
||||
$scope.formValues.NodeName = nodeName;
|
||||
|
@ -845,6 +756,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
if ($transition$.params().from) {
|
||||
loadFromContainerSpec();
|
||||
} else {
|
||||
$scope.state.containerIsLoaded = true;
|
||||
$scope.fromContainer = {};
|
||||
$scope.formValues.capabilities = $scope.areContainerCapabilitiesEnabled ? new ContainerCapabilities() : [];
|
||||
}
|
||||
|
@ -872,10 +784,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
|
||||
$scope.allowBindMounts = $scope.isAdminOrEndpointAdmin || endpoint.SecuritySettings.allowBindMountsForRegularUsers;
|
||||
$scope.allowPrivilegedMode = endpoint.SecuritySettings.allowPrivilegedModeForRegularUsers;
|
||||
|
||||
PluginService.loggingPlugins(apiVersion < 1.25).then(function success(loggingDrivers) {
|
||||
$scope.availableLoggingDrivers = loggingDrivers;
|
||||
});
|
||||
}
|
||||
|
||||
function validateForm(accessControlData, isAdmin) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue