Skip to content

Commit 3ab3d9a

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 b92abe5 commit 3ab3d9a

File tree

8 files changed

+1043
-579
lines changed

8 files changed

+1043
-579
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,192 @@
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: '@',
12+
entries: '=',
13+
envFromSelectorOptions: '<',
14+
selectorPlaceholder: '@'
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+
27+
ctrl.$id = _.uniqueId();
28+
ctrl.setFocusClass = 'edit-environment-from-set-focus-' + ctrl.$id;
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.entries && !ctrl.entries.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.envFromObjectSelected = function(index, entry, selected) {
65+
var newEnvFrom = {};
66+
67+
switch (selected.kind) {
68+
case 'Secret':
69+
newEnvFrom.secretRef = {
70+
name: selected.metadata.name
71+
};
72+
delete ctrl.envFromEntries[index].configMapRef;
73+
break;
74+
case 'ConfigMap':
75+
newEnvFrom.configMapRef = {
76+
name: selected.metadata.name
77+
};
78+
delete ctrl.envFromEntries[index].secretRef;
79+
break;
80+
}
81+
82+
_.assign(ctrl.envFromEntries[index], newEnvFrom);
83+
ctrl.updateEntries(ctrl.envFromEntries);
84+
};
85+
86+
ctrl.updateEntries = function(entries) {
87+
ctrl.entries = _.filter(entries, function (val) {
88+
return val.secretRef || val.configMapRef;
89+
});
90+
};
91+
92+
ctrl.updateEnvFromEntries = function(entries) {
93+
ctrl.envFromEntries = entries || [];
94+
95+
if(!ctrl.envFromEntries.length) {
96+
addEntry(ctrl.envFromEntries);
97+
}
98+
99+
_.each(ctrl.envFromEntries, function(entry) {
100+
if(entry) {
101+
if (entry.configMapRef) {
102+
entry.isReadonlyValue = !canI('configmaps', 'get');
103+
}
104+
105+
if (entry.secretRef) {
106+
entry.isReadonlyValue = !canI('secrets', 'get');
107+
}
108+
}
109+
});
110+
};
111+
112+
var getReferenceValue = function(option) {
113+
var referenceValue;
114+
115+
switch(option.kind) {
116+
case 'ConfigMap':
117+
referenceValue = _.find(ctrl.envFromEntries, {configMapRef: {name: option.metadata.name}});
118+
break;
119+
case 'Secret':
120+
referenceValue = _.find(ctrl.envFromEntries, {secretRef: {name: option.metadata.name}});
121+
break;
122+
}
123+
124+
return referenceValue;
125+
};
126+
127+
ctrl.checkEntries = function(option) {
128+
return !!(getReferenceValue(option));
129+
};
130+
131+
var findReferenceValueForEntries = function(entries, envFromSelectorOptions) {
132+
_.each(envFromSelectorOptions, function(option) {
133+
var referenceValue = getReferenceValue(option);
134+
135+
if (referenceValue) {
136+
_.set(referenceValue, 'selectedEnvFrom', option);
137+
}
138+
});
139+
};
140+
141+
angular.extend(ctrl, {
142+
dragControlListeners: {
143+
accept: function (sourceItemHandleScope, destSortableScope) {
144+
return sourceItemHandleScope.itemScope.sortableScope.$id === destSortableScope.$id;
145+
},
146+
orderChanged: function() {
147+
ctrl.editEnvironmentFromForm.$setDirty();
148+
}
149+
}
150+
});
151+
152+
ctrl.$onInit = function() {
153+
ctrl.updateEnvFromEntries(ctrl.entries);
154+
findReferenceValueForEntries(ctrl.envFromEntries, ctrl.envFromSelectorOptions);
155+
156+
if('cannotAdd' in $attrs) {
157+
ctrl.cannotAdd = true;
158+
}
159+
160+
if('cannotDelete' in $attrs) {
161+
ctrl.cannotDeleteAny = true;
162+
}
163+
164+
if('cannotSort' in $attrs) {
165+
ctrl.cannotSort = true;
166+
}
167+
168+
if('isReadonly' in $attrs) {
169+
ctrl.isReadonlyAny = true;
170+
}
171+
172+
if('showHeader' in $attrs) {
173+
ctrl.showHeader = true;
174+
}
175+
176+
if(ctrl.envFromEntries && !ctrl.envFromEntries.length) {
177+
addEntry(ctrl.envFromEntries);
178+
}
179+
};
180+
181+
ctrl.$onChanges = function(changes) {
182+
if(changes.entries) {
183+
ctrl.updateEnvFromEntries(changes.entries.currentValue);
184+
}
185+
186+
if(changes.envFromSelectorOptions) {
187+
findReferenceValueForEntries(ctrl.envFromEntries, changes.envFromSelectorOptions.currentValue);
188+
}
189+
};
190+
}
191+
})();
192+

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;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<ng-form name="$ctrl.editEnvironmentFromForm" novalidate>
2+
<div
3+
ng-if="$ctrl.showHeader"
4+
class="key-value-editor-entry key-value-editor-entry-header">
5+
<div class="form-group key-value-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="key-value-editor" as-sortable="$ctrl.dragControlListeners">
13+
<div
14+
class="key-value-editor-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
21+
class="form-group key-value-editor-input"
22+
ng-class="{ 'has-error': (forms.editEnvironmentFrom[uniqueForValue(unique, $index)].$invalid && forms.editEnvironmentFrom[uniqueForValue(unique, $index)].$touched) }">
23+
<div ng-if="$ctrl.isEnvFromReadonly(entry)" class="faux-input-group">
24+
<div class="faux-form-control readonly">
25+
Set to values in {{entry.selectedEnvFrom.kind | humanizeKind : true | lowercase}}
26+
<span
27+
ng-if="!('configmaps' | canI : 'get') || !('secrets' | canI : 'get')">
28+
{{entry.configMapRef.name || entry.secretRef.name}}
29+
</span>
30+
<a
31+
ng-if="'configmaps' | canI : 'get'"
32+
ng-href="{{entry.selectedEnvFrom | navigateResourceURL}}">
33+
{{entry.configMapRef.name || entry.secretRef.name}}
34+
</a>
35+
</div>
36+
</div>
37+
38+
<div ng-if="!$ctrl.isEnvFromReadonly(entry)">
39+
<div class="ui-select">
40+
<ui-select ng-model="entry.selectedEnvFrom"
41+
ng-required="entry.selectedEnvFrom"
42+
on-select="$ctrl.envFromObjectSelected($index, entry, $select.selected)"
43+
ng-class="{'{{$ctrl.setFocusClass}}' : $last}">
44+
<ui-select-match placeholder="Select a resource">
45+
<span>
46+
{{$select.selected.metadata.name}}
47+
<small class="text-muted">&ndash; {{$select.selected.kind | humanizeKind : true}}</small>
48+
</span>
49+
</ui-select-match>
50+
<ui-select-choices
51+
ui-disable-choice="$ctrl.checkEntries(source)"
52+
repeat="source in $ctrl.envFromSelectorOptions | filter : { metadata: { name: $select.search } } track by (source | uid)"
53+
group-by="$ctrl.groupByKind">
54+
<span ng-bind-html="source.metadata.name | highlight : $select.search"></span>
55+
</ui-select-choices>
56+
</ui-select>
57+
</div>
58+
</div>
59+
60+
<div>
61+
<span
62+
ng-if="(!$ctrl.cannotSort) && ($ctrl.entries.length > 1)"
63+
class="fa fa-bars sort-row"
64+
role="button"
65+
aria-label="Move row"
66+
aria-grabbed="false"
67+
as-sortable-item-handle></span>
68+
<a
69+
href=""
70+
class="pficon pficon-close delete-row as-sortable-item-delete"
71+
role="button"
72+
aria-label="Delete row"
73+
ng-hide="$ctrl.cannotDeleteAny"
74+
ng-click="$ctrl.deleteEntry($index, 1)"></a>
75+
<a
76+
ng-href="{{entry.selectedEnvFrom | navigateResourceURL}}"
77+
class="pficon"
78+
ng-show="entry.selectedEnvFrom"
79+
ng-click="$ctrl.viewDetail(entry)">View {{entry.selectedEnvFrom.kind | humanizeKind : true}}</a>
80+
</div>
81+
</div>
82+
</div>
83+
84+
<div class="key-value-editor-entry form-group" ng-if="(!$ctrl.cannotAdd)">
85+
<a
86+
href=""
87+
class="add-row-link"
88+
role="button"
89+
aria-label="Add row"
90+
ng-click="$ctrl.onAddRow()">{{ $ctrl.addRowLink }}</a>
91+
</div>
92+
</div>
93+
</ng-form>
94+

app/views/directives/edit-environment-variables.html

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<confirm-on-exit ng-if="$ctrl.canIUpdate && !$ctrl.ngReadonly" dirty="$ctrl.form.$dirty"></confirm-on-exit>
33
<div ng-repeat="container in $ctrl.containers">
44
<h3>Container {{container.name}}</h3>
5+
6+
<h4>Variables</h4>
57
<div ng-if="!$ctrl.canIUpdate || $ctrl.ngReadonly">
68
<span ng-if="!container.env.length">
79
No environment variables set in the {{$ctrl.apiObject.kind | humanizeKind}}
@@ -32,6 +34,21 @@ <h3>Container {{container.name}}</h3>
3234
add-row-with-selectors-link="Add Environment Variable Using a Config Map or Secret"
3335
show-header>
3436
</key-value-editor>
37+
38+
<h4>
39+
Environment From
40+
<span class="pficon pficon-info"
41+
aria-hidden="true"
42+
data-toggle="tooltip"
43+
data-original-title="Environment From lets you add all key-value pairs from a config map or secret as environment variables."></span>
44+
</h4>
45+
<edit-environment-from
46+
entries="container.envFrom"
47+
selector-placeholder="Secret/Config Map"
48+
env-from-selector-options="$ctrl.valueFromObjects"
49+
add-row-link="Add ALL Values from a Resource"
50+
show-header>
51+
</edit-environment-from>
3552
</div>
3653
<button
3754
class="btn btn-default"

0 commit comments

Comments
 (0)