Skip to content

Commit 034cf29

Browse files
committed
Support EnvFrom in the Env Editors
Add dropdown support to give the ability to add bulk additions within the environment editors
1 parent 3c27b2c commit 034cf29

File tree

11 files changed

+1094
-614
lines changed

11 files changed

+1094
-614
lines changed

app/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ <h1>JavaScript Required</h1>
307307
<script src="scripts/directives/deleteLink.js"></script>
308308
<script src="scripts/directives/editWebhookTriggers.js"></script>
309309
<script src="scripts/directives/editConfigMap.js"></script>
310+
<script src="scripts/directives/editEnvironmentFrom.js"></script>
310311
<script src="scripts/directives/events.js"></script>
311312
<script src="scripts/directives/eventsSidebar.js"></script>
312313
<script src="scripts/directives/eventsBadge.js"></script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
"use strict";
2+
(function() {
3+
angular.module("openshiftConsole").component('editEnvironmentFrom', {
4+
controller: [
5+
'$attrs',
6+
'$filter',
7+
'keyValueEditorUtils',
8+
EditEnvironmentFrom
9+
],
10+
bindings: {
11+
addRowLink: '@', // creates a link to "add row" and sets its text label
12+
entries: '=', // an array of objects containing configmaps and secrets
13+
envFromSelectorOptions: '<', // dropdown selector options, an array of objects
14+
selectorPlaceholder: '@' // placeholder copy for dropdown selector
15+
},
16+
templateUrl: 'views/directives/edit-environment-from.html'
17+
});
18+
19+
function EditEnvironmentFrom($attrs,
20+
$filter,
21+
utils) {
22+
var ctrl = this;
23+
24+
var canI = $filter('canI');
25+
var humanizeKind = $filter('humanizeKind');
26+
var uniqueId = _.uniqueId();
27+
28+
ctrl.setFocusClass = 'edit-environment-from-set-focus-' + uniqueId;
29+
30+
var addEntry = function(entries, entry) {
31+
entries && entries.push(entry || {});
32+
};
33+
34+
ctrl.onAddRow = function() {
35+
addEntry(ctrl.envFromEntries);
36+
utils.setFocusOn('.'+ ctrl.setFocusClass);
37+
};
38+
39+
ctrl.deleteEntry = function(start, deleteCount) {
40+
if(ctrl.envFromEntries && !ctrl.envFromEntries.length) {
41+
return;
42+
}
43+
44+
ctrl.envFromEntries.splice(start, deleteCount);
45+
if(!ctrl.envFromEntries.length && ctrl.addRowLink) {
46+
addEntry(ctrl.envFromEntries);
47+
}
48+
49+
ctrl.updateEntries(ctrl.envFromEntries);
50+
ctrl.editEnvironmentFromForm.$setDirty();
51+
};
52+
53+
ctrl.isEnvFromReadonly = function(entry) {
54+
return ctrl.isReadonlyAny ||
55+
entry.isReadonlyValue === true ||
56+
((entry.secretRef || entry.configMapRef) && !entry.selectedEnvFrom) ||
57+
_.isEmpty(ctrl.envFromSelectorOptions);
58+
};
59+
60+
ctrl.groupByKind = function(object) {
61+
return humanizeKind(object.kind);
62+
};
63+
64+
//ctrl.uniqueForValue = utils.uniqueForValue;
65+
ctrl.dragControlListeners = {
66+
accept: function (sourceItemHandleScope, destSortableScope) {
67+
return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id;
68+
},
69+
orderChanged: function() {
70+
ctrl.editEnvironmentFromForm.$setDirty();
71+
}
72+
};
73+
74+
ctrl.envFromObjectSelected = function(index, entry, selected) {
75+
var newEnvFrom = {};
76+
77+
switch (selected.kind) {
78+
case 'Secret':
79+
newEnvFrom.secretRef = {
80+
name: selected.metadata.name
81+
};
82+
delete ctrl.envFromEntries[index].configMapRef;
83+
break;
84+
case 'ConfigMap':
85+
newEnvFrom.configMapRef = {
86+
name: selected.metadata.name
87+
};
88+
delete ctrl.envFromEntries[index].secretRef;
89+
break;
90+
}
91+
92+
_.assign(ctrl.envFromEntries[index], newEnvFrom);
93+
ctrl.updateEntries(ctrl.envFromEntries);
94+
};
95+
96+
ctrl.updateEntries = function(entries) {
97+
ctrl.entries = _.filter(entries, function (val) {
98+
return val.secretRef || val.configMapRef;
99+
});
100+
};
101+
102+
var updateEnvFromEntries = function(entries) {
103+
ctrl.envFromEntries = entries || [];
104+
105+
if(!ctrl.envFromEntries.length) {
106+
addEntry(ctrl.envFromEntries);
107+
}
108+
109+
_.each(ctrl.envFromEntries, function(entry) {
110+
if(entry) {
111+
if(entry.configMapRef && !canI('configmaps', 'get')) {
112+
entry.isReadonlyValue = true;
113+
}
114+
115+
if(entry.secretRef && !canI('secrets', 'get')) {
116+
entry.isReadonlyValue = true;
117+
}
118+
}
119+
});
120+
};
121+
122+
var getReferenceValue = function(option) {
123+
var referenceValue;
124+
125+
switch(option.kind) {
126+
case 'ConfigMap':
127+
referenceValue = _.find(ctrl.envFromEntries, {configMapRef: {name: option.metadata.name}});
128+
break;
129+
case 'Secret':
130+
referenceValue = _.find(ctrl.envFromEntries, {secretRef: {name: option.metadata.name}});
131+
break;
132+
}
133+
134+
return referenceValue;
135+
};
136+
137+
ctrl.checkEntries = function(option) {
138+
return !!(getReferenceValue(option));
139+
};
140+
141+
var findReferenceValueForEntries = function(entries, envFromSelectorOptions) {
142+
ctrl.cannotAdd = (ctrl.isReadonlyAny || _.isEmpty(envFromSelectorOptions));
143+
144+
if(envFromSelectorOptions) {
145+
_.each(envFromSelectorOptions, function(option) {
146+
var referenceValue = getReferenceValue(option);
147+
148+
if (referenceValue) {
149+
_.set(referenceValue, 'selectedEnvFrom', option);
150+
}
151+
});
152+
}
153+
};
154+
155+
ctrl.$onInit = function() {
156+
updateEnvFromEntries(ctrl.entries);
157+
findReferenceValueForEntries(ctrl.entries, ctrl.envFromSelectorOptions);
158+
159+
if('cannotDelete' in $attrs) {
160+
ctrl.cannotDeleteAny = true;
161+
}
162+
163+
if('cannotSort' in $attrs) {
164+
ctrl.cannotSort = true;
165+
}
166+
167+
if('isReadonly' in $attrs) {
168+
ctrl.isReadonlyAny = true;
169+
}
170+
171+
if('showHeader' in $attrs) {
172+
ctrl.showHeader = true;
173+
}
174+
175+
if(ctrl.envFromEntries && !ctrl.envFromEntries.length) {
176+
addEntry(ctrl.envFromEntries);
177+
}
178+
};
179+
180+
ctrl.$onChanges = function(changes) {
181+
if(changes.entries) {
182+
updateEnvFromEntries(changes.entries.currentValue);
183+
}
184+
185+
if(changes.envFromSelectorOptions) {
186+
findReferenceValueForEntries(ctrl.envFromEntries, changes.envFromSelectorOptions.currentValue);
187+
}
188+
};
189+
}
190+
})();
191+

app/scripts/services/environment.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ angular.module("openshiftConsole")
2121
var containers = getContainers(object);
2222
_.each(containers, function(container) {
2323
container.env = container.env || [];
24+
container.envFrom = container.envFrom || [];
2425
});
2526
},
2627

@@ -50,7 +51,7 @@ angular.module("openshiftConsole")
5051
return false;
5152
}
5253

53-
var i, leftEnv, rightEnv;
54+
var i, leftEnv, rightEnv, leftEnvFrom, rightEnvFrom;
5455
for (i = 0; i < leftContainers.length; i++) {
5556
// If a container name has changed, consider it a conflict.
5657
if (leftContainers[i].name !== rightContainers[i].name) {
@@ -60,7 +61,11 @@ angular.module("openshiftConsole")
6061
// Check if any of the variable names or values are different.
6162
leftEnv = leftContainers[i].env || [];
6263
rightEnv = rightContainers[i].env || [];
63-
if (!_.isEqual(leftEnv, rightEnv)) {
64+
65+
leftEnvFrom = leftContainers[i].envFrom || [];
66+
rightEnvFrom = rightContainers[i].envFrom || [];
67+
68+
if (!_.isEqual(leftEnv, rightEnv) || !_.isEqual(leftEnvFrom, rightEnvFrom)) {
6469
return false;
6570
}
6671
}
@@ -78,6 +83,7 @@ angular.module("openshiftConsole")
7883
var targetContainers = getContainers(copy);
7984
for (i = 0; i < targetContainers.length; i++) {
8085
targetContainers[i].env = _.get(sourceContainers, [i, 'env'], []);
86+
targetContainers[i].envFrom = _.get(sourceContainers, [i, 'envFrom'], []);
8187
}
8288

8389
return copy;

app/styles/_kve.less

+34-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Angular Key Value Editor styles
22

3-
.key-value-editor {
3+
.key-value-editor,
4+
.environment-from-editor {
45
&.as-sortable-dragging {
56
.as-sortable-item-delete,
67
.input-group-addon,
@@ -101,21 +102,47 @@
101102
border-collapse: separate;
102103
display: table;
103104
position: relative;
105+
&.faux-input-single-input {
106+
width: 100%;
107+
}
104108
}
105109

106-
.key-value-editor-buttons {
110+
.key-value-editor-buttons,
111+
.environment-from-editor-button {
107112
position: absolute;
108113
right: 0;
109114
top: 0;
110115
width: (@as-sortable-item-button-width * 2);
111116
}
112117

113-
.key-value-editor-entry {
118+
.key-value-editor-entry,
119+
.environment-from-entry {
114120
display: table;
115121
padding-right: (@as-sortable-item-button-width * 2);
116122
position: relative;
117123
table-layout: fixed;
118124
width: 100%;
125+
@media(min-width: @screen-md-min) {
126+
.environment-from-editor-button {
127+
float: left;
128+
padding-right: 5px;
129+
position: relative;
130+
width: 50%;
131+
}
132+
}
133+
.environment-from-input {
134+
float: left;
135+
padding-right: 5px;
136+
width: 100%;
137+
@media(min-width: @screen-md-min) {
138+
width: 50%;
139+
}
140+
.faux-input-group,
141+
.ui-select {
142+
float: left;
143+
width: 100%;
144+
}
145+
}
119146
}
120147

121148
.key-value-editor-input .ui-select {
@@ -140,10 +167,12 @@
140167
width: 50%;
141168
}
142169

143-
.key-value-editor-entry-header {
170+
.key-value-editor-entry-header,
171+
.environment-from-editor-entry-header {
144172
padding-right: (@as-sortable-item-button-width * 2);
145173
}
146174

147-
.key-value-editor-header {
175+
.key-value-editor-header,
176+
.environment-from-editor-header {
148177
margin-bottom: 5px;
149178
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<ng-form name="$ctrl.editEnvironmentFromForm" novalidate>
2+
<div
3+
ng-if="$ctrl.showHeader"
4+
class="environment-from-entry environment-from-editor-entry-header">
5+
<div class="form-group environment-from-editor-header value-header">
6+
<div class="input-group">
7+
<span class="help-block">{{$ctrl.selectorPlaceholder}}</span>
8+
</div>
9+
</div>
10+
</div>
11+
12+
<div ng-model="$ctrl.entries" class="environment-from-editor" as-sortable="$ctrl.dragControlListeners">
13+
<div
14+
class="environment-from-entry"
15+
ng-class-odd="'odd'"
16+
ng-class-even="'even'"
17+
ng-repeat="entry in $ctrl.envFromEntries"
18+
as-sortable-item>
19+
20+
<div class="form-group environment-from-input">
21+
<div ng-if="$ctrl.isEnvFromReadonly(entry)" class="faux-input-group">
22+
<div ng-if="!entry.configMapRef.name && !entry.secretRef.name">
23+
No secrets or config maps have been added as Environment From.
24+
</div>
25+
<div ng-if="entry.configMapRef.name || entry.secretRef.name" class="faux-form-control readonly">
26+
Use all keys and values from
27+
<span ng-if="entry.configMapRef.name">config map {{entry.configMapRef.name}}</span>
28+
<span ng-if="entry.secretRef.name">secret {{entry.secretRef.name}}</span>
29+
</div>
30+
</div>
31+
32+
<div ng-if="!$ctrl.isEnvFromReadonly(entry)">
33+
<div class="ui-select">
34+
<ui-select ng-model="entry.selectedEnvFrom"
35+
ng-required="entry.selectedEnvFrom"
36+
on-select="$ctrl.envFromObjectSelected($index, entry, $select.selected)"
37+
ng-class="{'{{$ctrl.setFocusClass}}' : $last}">
38+
<ui-select-match placeholder="Select a resource">
39+
<span>
40+
{{$select.selected.metadata.name}}
41+
<small class="text-muted">&ndash; {{$select.selected.kind | humanizeKind : true}}</small>
42+
</span>
43+
</ui-select-match>
44+
<ui-select-choices
45+
ui-disable-choice="$ctrl.checkEntries(source)"
46+
repeat="source in $ctrl.envFromSelectorOptions | filter : { metadata: { name: $select.search } } track by (source | uid)"
47+
group-by="$ctrl.groupByKind">
48+
<span ng-bind-html="source.metadata.name | highlight : $select.search"></span>
49+
</ui-select-choices>
50+
</ui-select>
51+
</div>
52+
</div>
53+
</div>
54+
55+
<div ng-if="!$ctrl.isEnvFromReadonly(entry)" class="environment-from-editor-button">
56+
<span
57+
ng-if="!$ctrl.cannotSort"
58+
class="fa fa-bars sort-row"
59+
role="button"
60+
aria-label="Move row"
61+
aria-grabbed="false"
62+
as-sortable-item-handle></span>
63+
<a
64+
ng-if="!$ctrl.cannotDeleteAny"
65+
href=""
66+
class="pficon pficon-close delete-row as-sortable-item-delete"
67+
role="button"
68+
aria-label="Delete row"
69+
ng-click="$ctrl.deleteEntry($index, 1)"></a>
70+
</div>
71+
</div>
72+
73+
<div class="environment-from-entry form-group" ng-if="!$ctrl.cannotAdd">
74+
<a
75+
href=""
76+
class="add-row-link"
77+
role="button"
78+
ng-click="$ctrl.onAddRow()">{{ $ctrl.addRowLink }}</a>
79+
</div>
80+
</div>
81+
</ng-form>

0 commit comments

Comments
 (0)