feat(configurations): Review UI/UX configurations (#4691)

* feat(configurations): Review UI/UX configurations

* feat(configurations): fix binary secret value

* fix(frontend): populate data between simple and advanced modes (#4503)

* fix(configuration): parseYaml before create configuration

* fix(configurations): change c to C in ConfigurationOwner

* fix(application): change configuration index to configuration key in the view

* fix(configuration): resolve problem in application create with configuration not overriden.

* fix(configuration): fix bad import in helper

Co-authored-by: Simon Meng <simon.meng@portainer.io>
pull/4774/head
Maxime Bajeux 2021-01-25 02:14:35 +01:00 committed by GitHub
parent 46ff8a01bc
commit 41308d570d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 246 additions and 73 deletions

View File

@ -3,13 +3,13 @@
Data Data
</div> </div>
<div class="form-group"> <div class="form-group" ng-if="$ctrl.isCreation">
<div class="col-sm-12"> <div class="col-sm-12">
<p> <p>
<a class="small interactive" ng-if="$ctrl.formValues.IsSimple" ng-click="$ctrl.formValues.IsSimple = false"> <a class="small interactive" ng-if="$ctrl.formValues.IsSimple" ng-click="$ctrl.showAdvancedMode()">
<i class="fa fa-list-ol space-right" aria-hidden="true"></i> Advanced mode <i class="fa fa-list-ol space-right" aria-hidden="true"></i> Advanced mode
</a> </a>
<a class="small interactive" ng-if="!$ctrl.formValues.IsSimple" ng-click="$ctrl.formValues.IsSimple = true"> <a class="small interactive" ng-if="!$ctrl.formValues.IsSimple" ng-click="$ctrl.showSimpleMode()">
<i class="fa fa-edit space-right" aria-hidden="true"></i> Simple mode <i class="fa fa-edit space-right" aria-hidden="true"></i> Simple mode
</a> </a>
</p> </p>
@ -61,7 +61,7 @@
</div> </div>
</div> </div>
<div class="form-group" ng-if="$ctrl.formValues.IsSimple"> <div class="form-group" ng-if="$ctrl.formValues.IsSimple && !entry.IsBinary">
<label for="configuration_data_value_{{ index }}" class="col-sm-1 control-label text-left">Value</label> <label for="configuration_data_value_{{ index }}" class="col-sm-1 control-label text-left">Value</label>
<div class="col-sm-11"> <div class="col-sm-11">
<textarea <textarea
@ -80,6 +80,13 @@
</div> </div>
</div> </div>
<div class="form-group" ng-if="$ctrl.formValues.IsSimple && entry.IsBinary">
<label for="configuration_data_value_{{ index }}" class="col-sm-1 control-label text-left">Value</label>
<div class="col-sm-11 control-label small text-muted text-left"
>Binary data <portainer-tooltip position="bottom" message="This key holds binary data and cannot be displayed."></portainer-tooltip
></div>
</div>
<div class="form-group" ng-if="$ctrl.formValues.IsSimple"> <div class="form-group" ng-if="$ctrl.formValues.IsSimple">
<div class="col-sm-1"></div> <div class="col-sm-1"></div>
<div class="col-sm-11"> <div class="col-sm-11">

View File

@ -4,5 +4,6 @@ angular.module('portainer.kubernetes').component('kubernetesConfigurationData',
bindings: { bindings: {
formValues: '=', formValues: '=',
isValid: '=', isValid: '=',
isCreation: '=',
}, },
}); });

View File

@ -1,7 +1,10 @@
import angular from 'angular'; import angular from 'angular';
import _ from 'lodash-es'; import _ from 'lodash-es';
import { KubernetesConfigurationFormValuesDataEntry } from 'Kubernetes/models/configuration/formvalues'; import chardet from 'chardet';
import { Base64 } from 'js-base64';
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper'; import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
import { KubernetesConfigurationFormValuesEntry } from 'Kubernetes/models/configuration/formvalues';
class KubernetesConfigurationDataController { class KubernetesConfigurationDataController {
/* @ngInject */ /* @ngInject */
@ -12,6 +15,8 @@ class KubernetesConfigurationDataController {
this.editorUpdateAsync = this.editorUpdateAsync.bind(this); this.editorUpdateAsync = this.editorUpdateAsync.bind(this);
this.onFileLoad = this.onFileLoad.bind(this); this.onFileLoad = this.onFileLoad.bind(this);
this.onFileLoadAsync = this.onFileLoadAsync.bind(this); this.onFileLoadAsync = this.onFileLoadAsync.bind(this);
this.showSimpleMode = this.showSimpleMode.bind(this);
this.showAdvancedMode = this.showAdvancedMode.bind(this);
} }
onChangeKey() { onChangeKey() {
@ -20,7 +25,7 @@ class KubernetesConfigurationDataController {
} }
addEntry() { addEntry() {
this.formValues.Data.push(new KubernetesConfigurationFormValuesDataEntry()); this.formValues.Data.push(new KubernetesConfigurationFormValuesEntry());
} }
removeEntry(index) { removeEntry(index) {
@ -37,9 +42,20 @@ class KubernetesConfigurationDataController {
} }
async onFileLoadAsync(event) { async onFileLoadAsync(event) {
const entry = new KubernetesConfigurationFormValuesDataEntry(); const entry = new KubernetesConfigurationFormValuesEntry();
const encoding = chardet.detect(Buffer.from(event.target.result));
const decoder = new TextDecoder(encoding);
entry.Key = event.target.fileName; entry.Key = event.target.fileName;
entry.Value = event.target.result; entry.IsBinary = KubernetesConfigurationHelper.isBinary(encoding);
if (!entry.IsBinary) {
entry.Value = decoder.decode(event.target.result);
} else {
const stringValue = decoder.decode(event.target.result);
entry.Value = Base64.encode(stringValue);
}
this.formValues.Data.push(entry); this.formValues.Data.push(entry);
this.onChangeKey(); this.onChangeKey();
} }
@ -53,10 +69,20 @@ class KubernetesConfigurationDataController {
const temporaryFileReader = new FileReader(); const temporaryFileReader = new FileReader();
temporaryFileReader.fileName = file.name; temporaryFileReader.fileName = file.name;
temporaryFileReader.onload = this.onFileLoad; temporaryFileReader.onload = this.onFileLoad;
temporaryFileReader.readAsText(file); temporaryFileReader.readAsArrayBuffer(file);
} }
} }
showSimpleMode() {
this.formValues.IsSimple = true;
this.formValues.Data = KubernetesConfigurationHelper.parseYaml(this.formValues);
}
showAdvancedMode() {
this.formValues.IsSimple = false;
this.formValues.DataYaml = KubernetesConfigurationHelper.parseData(this.formValues);
}
$onInit() { $onInit() {
this.state = { this.state = {
duplicateKeys: {}, duplicateKeys: {},

View File

@ -1,8 +1,8 @@
import _ from 'lodash-es'; import _ from 'lodash-es';
import YAML from 'yaml';
import { KubernetesConfigMap } from 'Kubernetes/models/config-map/models'; import { KubernetesConfigMap } from 'Kubernetes/models/config-map/models';
import { KubernetesConfigMapCreatePayload, KubernetesConfigMapUpdatePayload } from 'Kubernetes/models/config-map/payloads'; import { KubernetesConfigMapCreatePayload, KubernetesConfigMapUpdatePayload } from 'Kubernetes/models/config-map/payloads';
import { KubernetesPortainerConfigurationOwnerLabel } from 'Kubernetes/models/configuration/models'; import { KubernetesPortainerConfigurationOwnerLabel } from 'Kubernetes/models/configuration/models';
import { KubernetesConfigurationFormValuesEntry } from 'Kubernetes/models/configuration/formvalues';
class KubernetesConfigMapConverter { class KubernetesConfigMapConverter {
/** /**
@ -16,7 +16,23 @@ class KubernetesConfigMapConverter {
res.ConfigurationOwner = data.metadata.labels ? data.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] : ''; res.ConfigurationOwner = data.metadata.labels ? data.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] : '';
res.CreationDate = data.metadata.creationTimestamp; res.CreationDate = data.metadata.creationTimestamp;
res.Yaml = yaml ? yaml.data : ''; res.Yaml = yaml ? yaml.data : '';
res.Data = data.data;
res.Data = _.concat(
_.map(data.data, (value, key) => {
const entry = new KubernetesConfigurationFormValuesEntry();
entry.Key = key;
entry.Value = value;
return entry;
}),
_.map(data.binaryData, (value, key) => {
const entry = new KubernetesConfigurationFormValuesEntry();
entry.Key = key;
entry.Value = value;
entry.IsBinary = true;
return entry;
})
);
return res; return res;
} }
@ -41,7 +57,14 @@ class KubernetesConfigMapConverter {
res.metadata.namespace = data.Namespace; res.metadata.namespace = data.Namespace;
const configurationOwner = _.truncate(data.ConfigurationOwner, { length: 63, omission: '' }); const configurationOwner = _.truncate(data.ConfigurationOwner, { length: 63, omission: '' });
res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = configurationOwner; res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = configurationOwner;
res.data = data.Data;
_.forEach(data.Data, (entry) => {
if (entry.IsBinary) {
res.binaryData[entry.Key] = entry.Value;
} else {
res.data[entry.Key] = entry.Value;
}
});
return res; return res;
} }
@ -54,7 +77,13 @@ class KubernetesConfigMapConverter {
res.metadata.name = data.Name; res.metadata.name = data.Name;
res.metadata.namespace = data.Namespace; res.metadata.namespace = data.Namespace;
res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = data.ConfigurationOwner; res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = data.ConfigurationOwner;
res.data = data.Data; _.forEach(data.Data, (entry) => {
if (entry.IsBinary) {
res.binaryData[entry.Key] = entry.Value;
} else {
res.data[entry.Key] = entry.Value;
}
});
return res; return res;
} }
@ -64,18 +93,7 @@ class KubernetesConfigMapConverter {
res.Name = formValues.Name; res.Name = formValues.Name;
res.Namespace = formValues.ResourcePool.Namespace.Name; res.Namespace = formValues.ResourcePool.Namespace.Name;
res.ConfigurationOwner = formValues.ConfigurationOwner; res.ConfigurationOwner = formValues.ConfigurationOwner;
if (formValues.IsSimple) { res.Data = formValues.Data;
res.Data = _.reduce(
formValues.Data,
(acc, entry) => {
acc[entry.Key] = entry.Value;
return acc;
},
{}
);
} else {
res.Data = YAML.parse(formValues.DataYaml);
}
return res; return res;
} }
} }

View File

@ -1,3 +1,4 @@
import _ from 'lodash-es';
import { KubernetesConfiguration, KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models'; import { KubernetesConfiguration, KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models';
class KubernetesConfigurationConverter { class KubernetesConfigurationConverter {
@ -9,7 +10,9 @@ class KubernetesConfigurationConverter {
res.Namespace = secret.Namespace; res.Namespace = secret.Namespace;
res.CreationDate = secret.CreationDate; res.CreationDate = secret.CreationDate;
res.Yaml = secret.Yaml; res.Yaml = secret.Yaml;
res.Data = secret.Data; _.forEach(secret.Data, (entry) => {
res.Data[entry.Key] = entry.Value;
});
res.ConfigurationOwner = secret.ConfigurationOwner; res.ConfigurationOwner = secret.ConfigurationOwner;
return res; return res;
} }
@ -22,7 +25,9 @@ class KubernetesConfigurationConverter {
res.Namespace = configMap.Namespace; res.Namespace = configMap.Namespace;
res.CreationDate = configMap.CreationDate; res.CreationDate = configMap.CreationDate;
res.Yaml = configMap.Yaml; res.Yaml = configMap.Yaml;
res.Data = configMap.Data; _.forEach(configMap.Data, (entry) => {
res.Data[entry.Key] = entry.Value;
});
res.ConfigurationOwner = configMap.ConfigurationOwner; res.ConfigurationOwner = configMap.ConfigurationOwner;
return res; return res;
} }

View File

@ -1,17 +1,30 @@
import { KubernetesSecretCreatePayload, KubernetesSecretUpdatePayload } from 'Kubernetes/models/secret/payloads'; import { KubernetesSecretCreatePayload, KubernetesSecretUpdatePayload } from 'Kubernetes/models/secret/payloads';
import { KubernetesApplicationSecret } from 'Kubernetes/models/secret/models'; import { KubernetesApplicationSecret } from 'Kubernetes/models/secret/models';
import YAML from 'yaml'; import { KubernetesPortainerConfigurationDataAnnotation } from 'Kubernetes/models/configuration/models';
import _ from 'lodash-es'; import _ from 'lodash-es';
import { KubernetesPortainerConfigurationOwnerLabel } from 'Kubernetes/models/configuration/models'; import { KubernetesPortainerConfigurationOwnerLabel } from 'Kubernetes/models/configuration/models';
import { KubernetesConfigurationFormValuesEntry } from 'Kubernetes/models/configuration/formvalues';
class KubernetesSecretConverter { class KubernetesSecretConverter {
static createPayload(secret) { static createPayload(secret) {
const res = new KubernetesSecretCreatePayload(); const res = new KubernetesSecretCreatePayload();
res.metadata.name = secret.Name; res.metadata.name = secret.Name;
res.metadata.namespace = secret.Namespace; res.metadata.namespace = secret.Namespace;
const configurationOwner = _.truncate(secret.configurationOwner, { length: 63, omission: '' }); const configurationOwner = _.truncate(secret.ConfigurationOwner, { length: 63, omission: '' });
res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = configurationOwner; res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = configurationOwner;
res.stringData = secret.Data;
let annotation = '';
_.forEach(secret.Data, (entry) => {
if (entry.IsBinary) {
res.data[entry.Key] = entry.Value;
annotation += annotation !== '' ? '|' + entry.Key : entry.Key;
} else {
res.stringData[entry.Key] = entry.Value;
}
});
if (annotation !== '') {
res.metadata.annotations[KubernetesPortainerConfigurationDataAnnotation] = annotation;
}
return res; return res;
} }
@ -20,7 +33,19 @@ class KubernetesSecretConverter {
res.metadata.name = secret.Name; res.metadata.name = secret.Name;
res.metadata.namespace = secret.Namespace; res.metadata.namespace = secret.Namespace;
res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = secret.ConfigurationOwner; res.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] = secret.ConfigurationOwner;
res.stringData = secret.Data;
let annotation = '';
_.forEach(secret.Data, (entry) => {
if (entry.IsBinary) {
res.data[entry.Key] = entry.Value;
annotation += annotation !== '' ? '|' + entry.Key : entry.Key;
} else {
res.stringData[entry.Key] = entry.Value;
}
});
if (annotation !== '') {
res.metadata.annotations[KubernetesPortainerConfigurationDataAnnotation] = annotation;
}
return res; return res;
} }
@ -32,7 +57,21 @@ class KubernetesSecretConverter {
res.ConfigurationOwner = payload.metadata.labels ? payload.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] : ''; res.ConfigurationOwner = payload.metadata.labels ? payload.metadata.labels[KubernetesPortainerConfigurationOwnerLabel] : '';
res.CreationDate = payload.metadata.creationTimestamp; res.CreationDate = payload.metadata.creationTimestamp;
res.Yaml = yaml ? yaml.data : ''; res.Yaml = yaml ? yaml.data : '';
res.Data = payload.data;
res.Data = _.map(payload.data, (value, key) => {
const annotations = payload.metadata.annotations ? payload.metadata.annotations[KubernetesPortainerConfigurationDataAnnotation] : '';
const entry = new KubernetesConfigurationFormValuesEntry();
entry.Key = key;
entry.IsBinary = _.includes(annotations, entry.Key);
if (!entry.IsBinary) {
entry.Value = atob(value);
} else {
entry.Value = value;
}
return entry;
});
return res; return res;
} }
@ -41,18 +80,7 @@ class KubernetesSecretConverter {
res.Name = formValues.Name; res.Name = formValues.Name;
res.Namespace = formValues.ResourcePool.Namespace.Name; res.Namespace = formValues.ResourcePool.Namespace.Name;
res.ConfigurationOwner = formValues.ConfigurationOwner; res.ConfigurationOwner = formValues.ConfigurationOwner;
if (formValues.IsSimple) { res.Data = formValues.Data;
res.Data = _.reduce(
formValues.Data,
(acc, entry) => {
acc[entry.Key] = entry.Value;
return acc;
},
{}
);
} else {
res.Data = YAML.parse(formValues.DataYaml);
}
return res; return res;
} }
} }

View File

@ -1,5 +1,7 @@
import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models'; import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models';
import { KubernetesConfigurationFormValuesEntry } from 'Kubernetes/models/configuration/formvalues';
import _ from 'lodash-es'; import _ from 'lodash-es';
import YAML from 'yaml';
class KubernetesConfigurationHelper { class KubernetesConfigurationHelper {
static getUsingApplications(config, applications) { static getUsingApplications(config, applications) {
@ -21,6 +23,10 @@ class KubernetesConfigurationHelper {
return _.startsWith(config.Name, 'default-token-'); return _.startsWith(config.Name, 'default-token-');
} }
static isBinary(encoding) {
return encoding !== '' && !_.includes(encoding, 'ISO') && !_.includes(encoding, 'UTF');
}
static setConfigurationUsed(config) { static setConfigurationUsed(config) {
config.Used = config.Applications && config.Applications.length !== 0; config.Used = config.Applications && config.Applications.length !== 0;
} }
@ -32,6 +38,31 @@ class KubernetesConfigurationHelper {
}); });
} }
static parseYaml(formValues) {
YAML.defaultOptions.customTags = ['binary'];
const data = _.map(YAML.parse(formValues.DataYaml), (value, key) => {
const entry = new KubernetesConfigurationFormValuesEntry();
entry.Key = key;
entry.Value = value;
const oldEntry = _.find(formValues.Data, { Key: entry.Key });
entry.IsBinary = oldEntry ? oldEntry.IsBinary : false;
return entry;
});
return data;
}
static parseData(formValues) {
const data = _.reduce(
formValues.Data,
(acc, entry) => {
acc[entry.Key] = entry.Value;
return acc;
},
{}
);
return YAML.stringify(data);
}
static isExternalConfiguration(configuration) { static isExternalConfiguration(configuration) {
return !configuration.ConfigurationOwner; return !configuration.ConfigurationOwner;
} }

View File

@ -11,7 +11,7 @@ const _KubernetesConfigMap = Object.freeze({
Namespace: '', Namespace: '',
Yaml: '', Yaml: '',
ConfigurationOwner: '', ConfigurationOwner: '',
Data: {}, Data: [],
}); });
export class KubernetesConfigMap { export class KubernetesConfigMap {

View File

@ -6,6 +6,7 @@ import { KubernetesCommonMetadataPayload } from 'Kubernetes/models/common/payloa
const _KubernetesConfigMapCreatePayload = Object.freeze({ const _KubernetesConfigMapCreatePayload = Object.freeze({
metadata: new KubernetesCommonMetadataPayload(), metadata: new KubernetesCommonMetadataPayload(),
data: {}, data: {},
binaryData: {},
}); });
export class KubernetesConfigMapCreatePayload { export class KubernetesConfigMapCreatePayload {
constructor() { constructor() {
@ -19,6 +20,7 @@ export class KubernetesConfigMapCreatePayload {
const _KubernetesConfigMapUpdatePayload = Object.freeze({ const _KubernetesConfigMapUpdatePayload = Object.freeze({
metadata: new KubernetesCommonMetadataPayload(), metadata: new KubernetesCommonMetadataPayload(),
data: {}, data: {},
binaryData: {},
}); });
export class KubernetesConfigMapUpdatePayload { export class KubernetesConfigMapUpdatePayload {
constructor() { constructor() {

View File

@ -20,16 +20,14 @@ export class KubernetesConfigurationFormValues {
} }
} }
/** const _KubernetesConfigurationFormValuesEntry = Object.freeze({
* KubernetesConfigurationEntry Model
*/
const _KubernetesConfigurationFormValuesDataEntry = Object.freeze({
Key: '', Key: '',
Value: '', Value: '',
IsBinary: false,
}); });
export class KubernetesConfigurationFormValuesDataEntry { export class KubernetesConfigurationFormValuesEntry {
constructor() { constructor() {
Object.assign(this, JSON.parse(JSON.stringify(_KubernetesConfigurationFormValuesDataEntry))); Object.assign(this, JSON.parse(JSON.stringify(_KubernetesConfigurationFormValuesEntry)));
} }
} }

View File

@ -1,4 +1,5 @@
export const KubernetesPortainerConfigurationOwnerLabel = 'io.portainer.kubernetes.configuration.owner'; export const KubernetesPortainerConfigurationOwnerLabel = 'io.portainer.kubernetes.configuration.owner';
export const KubernetesPortainerConfigurationDataAnnotation = 'io.portainer.kubernetes.configuration.data';
/** /**
* Configuration Model (Composite) * Configuration Model (Composite)

View File

@ -8,7 +8,7 @@ const _KubernetesApplicationSecret = Object.freeze({
CreationDate: '', CreationDate: '',
ConfigurationOwner: '', ConfigurationOwner: '',
Yaml: '', Yaml: '',
Data: {}, Data: [],
}); });
export class KubernetesApplicationSecret { export class KubernetesApplicationSecret {

View File

@ -7,6 +7,7 @@ const _KubernetesSecretCreatePayload = Object.freeze({
metadata: new KubernetesCommonMetadataPayload(), metadata: new KubernetesCommonMetadataPayload(),
type: 'Opaque', type: 'Opaque',
data: {}, data: {},
stringData: {},
}); });
export class KubernetesSecretCreatePayload { export class KubernetesSecretCreatePayload {
@ -22,6 +23,7 @@ const _KubernetesSecretUpdatePayload = Object.freeze({
metadata: new KubernetesCommonMetadataPayload(), metadata: new KubernetesCommonMetadataPayload(),
type: 'Opaque', type: 'Opaque',
data: {}, data: {},
stringData: {},
}); });
export class KubernetesSecretUpdatePayload { export class KubernetesSecretUpdatePayload {

View File

@ -115,8 +115,12 @@
<a href="https://kubernetes.io/docs/concepts/configuration/secret/#secret-types" target="_blank">official documentation</a>. <a href="https://kubernetes.io/docs/concepts/configuration/secret/#secret-types" target="_blank">official documentation</a>.
</div> </div>
</div> </div>
<kubernetes-configuration-data
<kubernetes-configuration-data ng-if="ctrl.formValues" form-values="ctrl.formValues" is-valid="ctrl.state.isDataValid"></kubernetes-configuration-data> ng-if="ctrl.formValues"
form-values="ctrl.formValues"
is-valid="ctrl.state.isDataValid"
is-creation="true"
></kubernetes-configuration-data>
<!-- actions --> <!-- actions -->
<div class="col-sm-12 form-section-title" style="margin-top: 10px;"> <div class="col-sm-12 form-section-title" style="margin-top: 10px;">

View File

@ -1,7 +1,8 @@
import angular from 'angular'; import angular from 'angular';
import _ from 'lodash-es'; import _ from 'lodash-es';
import { KubernetesConfigurationFormValues, KubernetesConfigurationFormValuesDataEntry } from 'Kubernetes/models/configuration/formvalues'; import { KubernetesConfigurationFormValues, KubernetesConfigurationFormValuesEntry } from 'Kubernetes/models/configuration/formvalues';
import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models'; import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models';
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
class KubernetesCreateConfigurationController { class KubernetesCreateConfigurationController {
/* @ngInject */ /* @ngInject */
@ -41,6 +42,9 @@ class KubernetesCreateConfigurationController {
try { try {
this.state.actionInProgress = true; this.state.actionInProgress = true;
this.formValues.ConfigurationOwner = this.Authentication.getUserDetails().username; this.formValues.ConfigurationOwner = this.Authentication.getUserDetails().username;
if (!this.formValues.IsSimple) {
this.formValues.Data = KubernetesConfigurationHelper.parseYaml(this.formValues);
}
await this.KubernetesConfigurationService.create(this.formValues); await this.KubernetesConfigurationService.create(this.formValues);
this.Notifications.success('Configuration succesfully created'); this.Notifications.success('Configuration succesfully created');
this.$state.go('kubernetes.configurations'); this.$state.go('kubernetes.configurations');
@ -76,7 +80,7 @@ class KubernetesCreateConfigurationController {
}; };
this.formValues = new KubernetesConfigurationFormValues(); this.formValues = new KubernetesConfigurationFormValues();
this.formValues.Data.push(new KubernetesConfigurationFormValuesDataEntry()); this.formValues.Data.push(new KubernetesConfigurationFormValuesEntry());
try { try {
const resourcePools = await this.KubernetesResourcePoolService.get(); const resourcePools = await this.KubernetesResourcePoolService.get();

View File

@ -77,7 +77,12 @@
<rd-widget> <rd-widget>
<rd-widget-body> <rd-widget-body>
<form ng-if="!ctrl.isSystemNamespace()" class="form-horizontal" name="kubernetesConfigurationCreationForm" autocomplete="off"> <form ng-if="!ctrl.isSystemNamespace()" class="form-horizontal" name="kubernetesConfigurationCreationForm" autocomplete="off">
<kubernetes-configuration-data ng-if="ctrl.formValues" form-values="ctrl.formValues" is-valid="ctrl.state.isDataValid"></kubernetes-configuration-data> <kubernetes-configuration-data
ng-if="ctrl.formValues"
form-values="ctrl.formValues"
is-valid="ctrl.state.isDataValid"
is-creation="false"
></kubernetes-configuration-data>
<!-- actions --> <!-- actions -->
<div class="col-sm-12 form-section-title" style="margin-top: 10px;"> <div class="col-sm-12 form-section-title" style="margin-top: 10px;">

View File

@ -1,7 +1,8 @@
import angular from 'angular'; import angular from 'angular';
import { KubernetesConfigurationFormValues, KubernetesConfigurationFormValuesDataEntry } from 'Kubernetes/models/configuration/formvalues'; import { KubernetesConfigurationFormValues } from 'Kubernetes/models/configuration/formvalues';
import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models'; import { KubernetesConfigurationTypes } from 'Kubernetes/models/configuration/models';
import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper'; import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper';
import KubernetesConfigurationConverter from 'Kubernetes/converters/configuration';
import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper'; import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper';
import _ from 'lodash-es'; import _ from 'lodash-es';
@ -14,6 +15,8 @@ class KubernetesConfigurationController {
Notifications, Notifications,
LocalStorage, LocalStorage,
KubernetesConfigurationService, KubernetesConfigurationService,
KubernetesConfigMapService,
KubernetesSecretService,
KubernetesResourcePoolService, KubernetesResourcePoolService,
ModalService, ModalService,
KubernetesApplicationService, KubernetesApplicationService,
@ -32,6 +35,8 @@ class KubernetesConfigurationController {
this.KubernetesEventService = KubernetesEventService; this.KubernetesEventService = KubernetesEventService;
this.KubernetesConfigurationTypes = KubernetesConfigurationTypes; this.KubernetesConfigurationTypes = KubernetesConfigurationTypes;
this.KubernetesNamespaceHelper = KubernetesNamespaceHelper; this.KubernetesNamespaceHelper = KubernetesNamespaceHelper;
this.KubernetesConfigMapService = KubernetesConfigMapService;
this.KubernetesSecretService = KubernetesSecretService;
this.onInit = this.onInit.bind(this); this.onInit = this.onInit.bind(this);
this.getConfigurationAsync = this.getConfigurationAsync.bind(this); this.getConfigurationAsync = this.getConfigurationAsync.bind(this);
@ -126,7 +131,18 @@ class KubernetesConfigurationController {
this.state.configurationLoading = true; this.state.configurationLoading = true;
const name = this.$transition$.params().name; const name = this.$transition$.params().name;
const namespace = this.$transition$.params().namespace; const namespace = this.$transition$.params().namespace;
this.configuration = await this.KubernetesConfigurationService.get(namespace, name); const [configMap, secret] = await Promise.allSettled([this.KubernetesConfigMapService.get(namespace, name), this.KubernetesSecretService.get(namespace, name)]);
if (secret.status === 'fulfilled') {
this.configuration = KubernetesConfigurationConverter.secretToConfiguration(secret.value);
this.formValues.Data = secret.value.Data;
} else {
this.configuration = KubernetesConfigurationConverter.configMapToConfiguration(configMap.value);
this.formValues.Data = configMap.value.Data;
}
this.formValues.ResourcePool = _.find(this.resourcePools, (resourcePool) => resourcePool.Namespace.Name === this.configuration.Namespace);
this.formValues.Id = this.configuration.Id;
this.formValues.Name = this.configuration.Name;
this.formValues.Type = this.configuration.Type;
} catch (err) { } catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve configuration'); this.Notifications.error('Failure', err, 'Unable to retrieve configuration');
} finally { } finally {
@ -211,20 +227,6 @@ class KubernetesConfigurationController {
await this.getConfiguration(); await this.getConfiguration();
await this.getApplications(this.configuration.Namespace); await this.getApplications(this.configuration.Namespace);
await this.getEvents(this.configuration.Namespace); await this.getEvents(this.configuration.Namespace);
this.formValues.ResourcePool = _.find(this.resourcePools, (resourcePool) => resourcePool.Namespace.Name === this.configuration.Namespace);
this.formValues.Id = this.configuration.Id;
this.formValues.Name = this.configuration.Name;
this.formValues.Type = this.configuration.Type;
this.formValues.Data = _.map(this.configuration.Data, (value, key) => {
if (this.configuration.Type === KubernetesConfigurationTypes.SECRET) {
value = atob(value);
}
this.formValues.DataYaml += key + ': ' + value + '\n';
const entry = new KubernetesConfigurationFormValuesDataEntry();
entry.Key = key;
entry.Value = value;
return entry;
});
await this.getConfigurations(); await this.getConfigurations();
} catch (err) { } catch (err) {
this.Notifications.error('Failure', err, 'Unable to load view data'); this.Notifications.error('Failure', err, 'Unable to load view data');

View File

@ -72,12 +72,16 @@
"babel-plugin-angularjs-annotate": "^0.10.0", "babel-plugin-angularjs-annotate": "^0.10.0",
"bootbox": "^5.4.0", "bootbox": "^5.4.0",
"bootstrap": "^3.4.0", "bootstrap": "^3.4.0",
"chardet": "^1.3.0",
"chart.js": "~2.6.0", "chart.js": "~2.6.0",
"codemirror": "~5.30.0", "codemirror": "~5.30.0",
"fast-json-patch": "^3.0.0-1", "fast-json-patch": "^3.0.0-1",
"file-system": "^2.2.2",
"filesize": "~3.3.0", "filesize": "~3.3.0",
"filesize-parser": "^1.5.0", "filesize-parser": "^1.5.0",
"fs": "^0.0.1-security",
"jquery": "^3.5.1", "jquery": "^3.5.1",
"js-base64": "^3.6.0",
"js-yaml": "^3.14.0", "js-yaml": "^3.14.0",
"lodash-es": "^4.17.15", "lodash-es": "^4.17.15",
"moment": "^2.21.0", "moment": "^2.21.0",

View File

@ -2411,6 +2411,11 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chardet@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-1.3.0.tgz#a56ed2d9e4517a7128721340a0cb9a10a8fac238"
integrity sha512-cyTQGGptIjIT+CMGT5J/0l9c6Fb+565GCFjjeUTKxUO7w3oR+FcNCMEKTn5xtVKaLFmladN7QF68IiQsv5Fbdw==
chart.js@~2.6.0: chart.js@~2.6.0:
version "2.6.0" version "2.6.0"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.6.0.tgz#308f9a4b0bfed5a154c14f5deb1d9470d22abe71" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.6.0.tgz#308f9a4b0bfed5a154c14f5deb1d9470d22abe71"
@ -4572,6 +4577,13 @@ file-loader@^1.1.11:
loader-utils "^1.0.2" loader-utils "^1.0.2"
schema-utils "^0.4.5" schema-utils "^0.4.5"
file-match@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/file-match/-/file-match-1.0.2.tgz#c9cad265d2c8adf3a81475b0df475859069faef7"
integrity sha1-ycrSZdLIrfOoFHWw30dYWQafrvc=
dependencies:
utils-extend "^1.0.6"
file-saver@^1.3.3: file-saver@^1.3.3:
version "1.3.8" version "1.3.8"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8" resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
@ -4582,6 +4594,14 @@ file-sync-cmp@^0.1.0:
resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b" resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b"
integrity sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs= integrity sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=
file-system@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/file-system/-/file-system-2.2.2.tgz#7d65833e3a2347dcd956a813c677153ed3edd987"
integrity sha1-fWWDPjojR9zZVqgTxncVPtPt2Yc=
dependencies:
file-match "^1.0.1"
utils-extend "^1.0.4"
file-type@5.2.0, file-type@^5.2.0: file-type@5.2.0, file-type@^5.2.0:
version "5.2.0" version "5.2.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6"
@ -4900,6 +4920,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fs@^0.0.1-security:
version "0.0.1-security"
resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4"
integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ=
fsevents@^1.2.7: fsevents@^1.2.7:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
@ -6586,6 +6611,11 @@ js-base64@^2.1.9:
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.1.tgz#c328374225d2e65569791ded73c258e2c59334c7" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.1.tgz#c328374225d2e65569791ded73c258e2c59334c7"
integrity sha512-G5x2saUTupU9D/xBY9snJs3TxvwX8EkpLFiYlPpDt/VmMHOXprnSU1nxiTmFbijCX4BLF/cMRIfAcC5BiMYgFQ== integrity sha512-G5x2saUTupU9D/xBY9snJs3TxvwX8EkpLFiYlPpDt/VmMHOXprnSU1nxiTmFbijCX4BLF/cMRIfAcC5BiMYgFQ==
js-base64@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.0.tgz#773e1de628f4f298d65a7e9842c50244751f5756"
integrity sha512-wVdUBYQeY2gY73RIlPrysvpYx+2vheGo8Y1SNQv/BzHToWpAZzJU7Z6uheKMAe+GLSBig5/Ps2nxg/8tRB73xg==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -10991,6 +11021,11 @@ utila@^0.4.0, utila@~0.4:
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
utils-extend@^1.0.4, utils-extend@^1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/utils-extend/-/utils-extend-1.0.8.tgz#ccfd7b64540f8e90ee21eec57769d0651cab8a5f"
integrity sha1-zP17ZFQPjpDuIe7Fd2nQZRyril8=
utils-merge@1.0.1: utils-merge@1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"