mirror of https://github.com/rancher/ui.git
385 lines
8.5 KiB
JavaScript
385 lines
8.5 KiB
JavaScript
import { isArray } from '@ember/array';
|
|
import EmberObject, { set, setProperties } from '@ember/object';
|
|
import Mixin from '@ember/object/mixin';
|
|
import C from 'ui/utils/constants';
|
|
import { debouncedObserver } from 'ui/utils/debounce';
|
|
|
|
const USER = 'user';
|
|
const SYSTEM = 'system';
|
|
const AFFINITY = 'affinity';
|
|
|
|
export const TYPE = {
|
|
USER,
|
|
SYSTEM,
|
|
AFFINITY
|
|
}
|
|
|
|
export function flattenLabelArrays(...lists) {
|
|
let out = {};
|
|
|
|
function flatten(row) {
|
|
if ( row.value === undefined )
|
|
{
|
|
delete out[row.key];
|
|
}
|
|
else
|
|
{
|
|
out[row.key] = row.value;
|
|
}
|
|
}
|
|
|
|
for ( let i = 0 ; i < lists.length ; i++ ) {
|
|
(lists[i]||[]).forEach(flatten);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
function isSoftUser(type,key) {
|
|
// Include actual user labels
|
|
if ( type === USER )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Don't include any affinity labels
|
|
if ( type === AFFINITY )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Don't include any system labels that are blacklisted (because they have their own controls, like global)
|
|
if ( C.SYSTEM_LABELS_WITH_CONTROL.indexOf(key) >= 0 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Include anything else
|
|
return true;
|
|
}
|
|
|
|
export default Mixin.create({
|
|
labelArray: null,
|
|
|
|
actions: {
|
|
addUserLabel() {
|
|
this.get('labelArray').pushObject(EmberObject.create({
|
|
type: USER,
|
|
key: '',
|
|
value: '',
|
|
}));
|
|
},
|
|
|
|
addSystemLabel() {
|
|
this.get('labelArray').pushObject(EmberObject.create({
|
|
type: SYSTEM,
|
|
key: '',
|
|
value: '',
|
|
}));
|
|
},
|
|
|
|
addAffinityLabel() {
|
|
this.get('labelArray').pushObject(EmberObject.create({
|
|
type: AFFINITY,
|
|
key: C.LABEL.SCHED_HOST_LABEL,
|
|
value: '',
|
|
}));
|
|
},
|
|
|
|
removeLabel(obj) {
|
|
this.get('labelArray').removeObject(obj);
|
|
},
|
|
|
|
pastedLabels(str, target) {
|
|
let ary = this.get('labelArray');
|
|
str = str.trim();
|
|
if ( str.indexOf('=') === -1 && str.indexOf(':') === -1)
|
|
{
|
|
// Just pasting a key
|
|
$(target).val(str);
|
|
return;
|
|
}
|
|
|
|
let lines = str.split(/\r?\n/);
|
|
lines.forEach((line) => {
|
|
line = line.trim();
|
|
if ( !line )
|
|
{
|
|
return;
|
|
}
|
|
|
|
let idx = line.indexOf('=');
|
|
if ( idx === -1 ) {
|
|
idx = line.indexOf(':');
|
|
}
|
|
|
|
let key = '';
|
|
let val = '';
|
|
if ( idx > 0 )
|
|
{
|
|
key = line.substr(0,idx).trim();
|
|
val = line.substr(idx+1).trim();
|
|
}
|
|
else
|
|
{
|
|
key = line.trim();
|
|
val = '';
|
|
}
|
|
|
|
let existing = ary.filterBy('key',key)[0];
|
|
if ( existing )
|
|
{
|
|
set(existing,'value',val);
|
|
}
|
|
else
|
|
{
|
|
ary.pushObject(EmberObject.create({key: key, value: val, type: USER}));
|
|
}
|
|
});
|
|
|
|
// Clean up empty user entries
|
|
let toRemove = [];
|
|
ary.filterBy('type',USER).forEach((item) => {
|
|
if ( !item.get('key') && !item.get('value') )
|
|
{
|
|
toRemove.push(item);
|
|
}
|
|
});
|
|
ary.removeObjects(toRemove);
|
|
},
|
|
},
|
|
|
|
// User labels are actual user ones, plus system ones that have no controls in the UI so they are manually entered.
|
|
userLabelArray: function() {
|
|
return (this.get('labelArray')||[]).filter((item) => {
|
|
return isSoftUser(item.get('type'), item.get('key'));
|
|
});
|
|
}.property('labelArray.@each.type'),
|
|
|
|
strictUserLabelArray: function() {
|
|
return (this.get('labelArray')||[]).filterBy('type',USER);
|
|
}.property('labelArray.@each.type'),
|
|
|
|
systemLabelArray: function() {
|
|
return (this.get('labelArray')||[]).filterBy('type',SYSTEM);
|
|
}.property('labelArray.@each.type'),
|
|
|
|
affinityLabelArray: function() {
|
|
return (this.get('labelArray')||[]).filterBy('type',AFFINITY);
|
|
}.property('labelArray.@each.type'),
|
|
|
|
getLabelObj: function(key) {
|
|
let lcKey = (key||'').toLowerCase();
|
|
let ary = this.get('labelArray');
|
|
let item;
|
|
|
|
// Try specific case first
|
|
for ( let i = 0 ; i < ary.get('length') ; i++ )
|
|
{
|
|
item = ary.objectAt(i);
|
|
if ( item.get('key') === key )
|
|
{
|
|
return item;
|
|
}
|
|
}
|
|
|
|
// Then case-insensitive
|
|
for ( var i = 0 ; i < ary.get('length') ; i++ )
|
|
{
|
|
item = ary.objectAt(i);
|
|
if ( item.get('key').toLowerCase() === lcKey )
|
|
{
|
|
return item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
getLabel: function(key) {
|
|
let obj = this.getLabelObj(key);
|
|
if ( obj )
|
|
{
|
|
return obj.get('value');
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
setLabel: function(key, value) {
|
|
let lcKey = (key||'').toLowerCase();
|
|
let type = 'user';
|
|
|
|
// Rancher keys are always lowercase
|
|
if ( lcKey.indexOf(C.LABEL.AFFINITY_PREFIX) === 0 )
|
|
{
|
|
type = 'affinity';
|
|
key = lcKey;
|
|
}
|
|
else if ( lcKey.indexOf(C.LABEL.SYSTEM_PREFIX) === 0 )
|
|
{
|
|
type = 'system';
|
|
key = lcKey;
|
|
}
|
|
|
|
let existing = this.getLabelObj(key);
|
|
if ( existing ) {
|
|
if ( existing.get('value') !== value ) {
|
|
setProperties(existing,{
|
|
value: value,
|
|
type: type,
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
existing = this.get('labelArray').pushObject(EmberObject.create({
|
|
key: key,
|
|
value: value,
|
|
type: type,
|
|
}));
|
|
}
|
|
|
|
return existing;
|
|
},
|
|
|
|
removeLabel: function(key, soft=false) {
|
|
if ( soft )
|
|
{
|
|
this.setLabel(key, undefined);
|
|
}
|
|
else
|
|
{
|
|
let existing = this.getLabelObj(key);
|
|
if ( existing )
|
|
{
|
|
this.get('labelArray').removeObject(existing);
|
|
}
|
|
}
|
|
},
|
|
|
|
initLabels: function(obj, onlyOfType, onlyKeys, readonlyKeys) {
|
|
let out = [];
|
|
|
|
if ( onlyKeys && !isArray(onlyKeys) )
|
|
{
|
|
onlyKeys = [onlyKeys];
|
|
}
|
|
|
|
if ( readonlyKeys && !isArray(readonlyKeys) )
|
|
{
|
|
readonlyKeys = [readonlyKeys];
|
|
}
|
|
|
|
Object.keys(obj||{}).forEach(function(key) {
|
|
let type = 'user';
|
|
if ( key.indexOf(C.LABEL.AFFINITY_PREFIX) === 0 )
|
|
{
|
|
type = 'affinity';
|
|
}
|
|
else if ( key.indexOf(C.LABEL.SYSTEM_PREFIX) === 0 )
|
|
{
|
|
type = 'system';
|
|
}
|
|
|
|
if ( C.LABELS_TO_IGNORE.indexOf(key) >= 0 )
|
|
{
|
|
// Skip ignored labels
|
|
return;
|
|
}
|
|
|
|
if ( onlyOfType )
|
|
{
|
|
// Strict User, only those with type actually == user
|
|
if ( onlyOfType === 'strictUser' && type !== 'user' ) {
|
|
return;
|
|
}
|
|
|
|
if ( onlyOfType === 'user' ) {
|
|
// Soft user := user + system things that don't have UI controls
|
|
if ( !isSoftUser(type, key) ) {
|
|
return;
|
|
}
|
|
} else if ( onlyOfType !== type ) {
|
|
// Generally the wrong type, for system or affinity
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( onlyKeys && onlyKeys.indexOf(key) === -1 )
|
|
{
|
|
// Skip labels of keys we don't care about
|
|
return;
|
|
}
|
|
|
|
out.push(EmberObject.create({
|
|
key: key,
|
|
value: obj[key]||'',
|
|
type: type,
|
|
readonly: readonlyKeys && readonlyKeys.indexOf(key) >= 0
|
|
}));
|
|
});
|
|
|
|
this.set('labelArray', out);
|
|
this.labelsChanged();
|
|
},
|
|
|
|
labelsChanged: debouncedObserver('labelArray.@each.{type,key,value}', function() {
|
|
// Make a map of the keys we care about, and combine multiple values together
|
|
let map = {};
|
|
(this.get('labelArray')||[]).forEach(function(row) {
|
|
let key = row.get('key') || '';
|
|
let type = row.get('type') || '';
|
|
|
|
// System and Affinity labels are always lowercase.
|
|
if ( type !== USER )
|
|
{
|
|
key = key.toLowerCase();
|
|
}
|
|
|
|
// Pass undefined through, for soft-delete
|
|
if ( row.get('value') === undefined )
|
|
{
|
|
map[key] = undefined;
|
|
return;
|
|
}
|
|
|
|
let value = row.get('value') || '';
|
|
|
|
// Skip empty keys, and system/affinity labels with no value
|
|
if ( !key || (type !== USER && value === ''))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// System and Affinity values used to be always lowercase.
|
|
//if ( type !== USER )
|
|
//{
|
|
// value = value.toLowerCase();
|
|
//}
|
|
|
|
// Affinity & System labels can be concatenated, Users just overwrite the previous value.
|
|
if ( map[key] && type !== USER )
|
|
{
|
|
map[key] = map[key]+',' + value;
|
|
}
|
|
else
|
|
{
|
|
map[key] = value;
|
|
}
|
|
});
|
|
|
|
// Then turn them back into an array because Ember hates maps.
|
|
let out = [];
|
|
Object.keys(map).forEach((key) => {
|
|
out.push({key: key, value: map[key]});
|
|
});
|
|
|
|
this.updateLabels(out);
|
|
}),
|
|
|
|
updateLabels(/*labels*/) {
|
|
// Override me to do something
|
|
},
|
|
});
|