mirror of https://github.com/rancher/dashboard.git
199 lines
5.0 KiB
JavaScript
199 lines
5.0 KiB
JavaScript
import { ANNOTATIONS_TO_IGNORE_REGEX, LABELS_TO_IGNORE_REGEX } from '@shell/config/labels-annotations';
|
|
import pickBy from 'lodash/pickBy';
|
|
import { findBy } from '@shell/utils/array';
|
|
import { matchesSomeRegex, coerceStringTypeToScalarType } from '@shell/utils/string';
|
|
import Resource, { DNS_LIKE_TYPES } from '@shell/plugins/dashboard-store/resource-class';
|
|
import { get } from '@shell/utils/object';
|
|
import {
|
|
displayKeyFor,
|
|
validateBoolean,
|
|
validateChars,
|
|
validateDnsLikeTypes,
|
|
validateLength,
|
|
} from '@shell/utils/validators';
|
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
import isString from 'lodash/isString';
|
|
import uniq from 'lodash/uniq';
|
|
|
|
import isEmpty from 'lodash/isEmpty';
|
|
|
|
const STRING_LIKE_TYPES = [
|
|
'string',
|
|
'date',
|
|
'blob',
|
|
'enum',
|
|
'multiline',
|
|
'masked',
|
|
'password',
|
|
'dnsLabel',
|
|
'hostname',
|
|
];
|
|
|
|
export default class NormanModel extends Resource {
|
|
setLabels(val) {
|
|
const all = this.labels || {};
|
|
const wasIgnored = pickBy(all, (value, key) => {
|
|
return matchesSomeRegex(key, LABELS_TO_IGNORE_REGEX);
|
|
});
|
|
|
|
this['labels'] = { ...wasIgnored, ...val };
|
|
}
|
|
|
|
setLabel(key, val) {
|
|
if ( val ) {
|
|
if ( !this.labels ) {
|
|
this.labels = {};
|
|
}
|
|
|
|
this.labels[key] = val;
|
|
} else if ( this.labels ) {
|
|
this.labels[key] = undefined;
|
|
delete this.labels[key];
|
|
}
|
|
}
|
|
|
|
setAnnotations(val) {
|
|
const all = this.annotations || {};
|
|
const wasIgnored = pickBy(all, (value, key) => {
|
|
return matchesSomeRegex(key, ANNOTATIONS_TO_IGNORE_REGEX);
|
|
});
|
|
|
|
this['annotations'] = { ...wasIgnored, ...val };
|
|
}
|
|
|
|
setAnnotation(key, val) {
|
|
if ( val ) {
|
|
if ( !this.annotations ) {
|
|
this.annotations = {};
|
|
}
|
|
|
|
this.annotations[key] = val;
|
|
} else if ( this.annotations ) {
|
|
this.annotations[key] = undefined;
|
|
delete this.annotations[key];
|
|
}
|
|
}
|
|
|
|
setResourceQuotas(spec) {
|
|
const keys = ['resourceQuota', 'namespaceDefaultResourceQuota'];
|
|
|
|
keys.forEach((key) => {
|
|
this[key] = { ...spec[key] };
|
|
});
|
|
}
|
|
|
|
isCondition(condition, withStatus = 'True') {
|
|
if ( !this.conditions ) {
|
|
return false;
|
|
}
|
|
|
|
const entry = findBy((this.conditions || []), 'type', condition);
|
|
|
|
if ( !entry ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !withStatus ) {
|
|
return true;
|
|
}
|
|
|
|
return (entry.status || '').toLowerCase() === `${ withStatus }`.toLowerCase();
|
|
}
|
|
|
|
/**
|
|
* Check this instance is valid against
|
|
* - the schema's resource fields
|
|
* - also calls super.validationErrors
|
|
*/
|
|
validationErrors(data = this, opt = { ignoreFields: undefined }) {
|
|
const errors = [];
|
|
const {
|
|
type: originalType,
|
|
schema
|
|
} = data;
|
|
const type = normalizeType(originalType);
|
|
|
|
if ( !originalType ) {
|
|
// eslint-disable-next-line
|
|
console.warn(this.t('validation.noType'), data);
|
|
|
|
return errors;
|
|
}
|
|
|
|
if ( !schema ) {
|
|
// eslint-disable-next-line
|
|
// console.warn(this.t('validation.noSchema'), originalType, data);
|
|
|
|
return errors;
|
|
}
|
|
|
|
const fields = schema.resourceFields || {};
|
|
const keys = Object.keys(fields);
|
|
let field, key, val, displayKey;
|
|
|
|
for ( let i = 0 ; i < keys.length ; i++ ) {
|
|
const fieldErrors = [];
|
|
|
|
key = keys[i];
|
|
field = fields[key];
|
|
val = get(data, key);
|
|
displayKey = displayKeyFor(type, key, this.$rootGetters);
|
|
|
|
const fieldType = field?.type ? normalizeType(field.type) : null;
|
|
const valIsString = isString(val);
|
|
|
|
if ( opt.ignoreFields && opt.ignoreFields.includes(key) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( val === undefined ) {
|
|
val = null;
|
|
}
|
|
|
|
if (valIsString) {
|
|
if (fieldType) {
|
|
data[key] = coerceStringTypeToScalarType(val, fieldType);
|
|
}
|
|
|
|
// Empty strings on nullable string fields -> null
|
|
if ( field.nullable && val.length === 0 && STRING_LIKE_TYPES.includes(fieldType)) {
|
|
val = null;
|
|
|
|
data[key] = val;
|
|
}
|
|
}
|
|
if (fieldType === 'boolean') {
|
|
validateBoolean(val, field, displayKey, this.$rootGetters, fieldErrors);
|
|
} else {
|
|
validateLength(val, field, displayKey, this.$rootGetters, fieldErrors);
|
|
validateChars(val, field, displayKey, this.$rootGetters, fieldErrors);
|
|
}
|
|
|
|
if (fieldErrors.length > 0) {
|
|
fieldErrors.push(this.t('validation.required', { key: displayKey }));
|
|
errors.push(...fieldErrors);
|
|
continue;
|
|
}
|
|
|
|
// IDs claim to be these but are lies...
|
|
if ( key !== 'id' && !isEmpty(val) && DNS_LIKE_TYPES.includes(fieldType) ) {
|
|
// DNS types should be lowercase
|
|
const tolower = (val || '').toLowerCase();
|
|
|
|
if ( tolower !== val ) {
|
|
val = tolower;
|
|
|
|
data[key] = val;
|
|
}
|
|
|
|
fieldErrors.push(...validateDnsLikeTypes(val, fieldType, displayKey, this.$rootGetters, fieldErrors));
|
|
}
|
|
errors.push(...fieldErrors);
|
|
}
|
|
|
|
const rootErrors = super.validationErrors(this, opt);
|
|
|
|
return uniq([...errors, ...rootErrors]);
|
|
}
|
|
}
|