revert NameNsDescription and filter annotations, labels in create-edit-view

This commit is contained in:
Nancy Butler 2020-04-22 17:21:18 -07:00
parent 6249c766ab
commit b8a996c43f
18 changed files with 147 additions and 84 deletions

View File

@ -1,6 +1,7 @@
<script>
import { sortBy } from '@/utils/sort';
import { NAMESPACE } from '@/config/types';
import { DESCRIPTION } from '@/config/labels-annotations';
import { _VIEW, _EDIT } from '@/config/query-params';
import LabeledInput from '@/components/form/LabeledInput';
import InputWithSelect from '@/components/form/InputWithSelect';
@ -12,52 +13,38 @@ export default {
},
props: {
/* metadata or any object with name, namespace, fields to be modified */
value: {
type: Object,
required: true,
},
description: {
type: String,
default: null
},
mode: {
type: String,
required: true,
},
namespaced: {
type: Boolean,
default: true,
},
extraColumns: {
type: Array,
default: () => []
},
extraDetailColumns: {
type: Array,
default: () => []
},
nameEditable: {
type: Boolean,
default: false,
},
nameLabel: {
type: String,
default: 'Name'
},
namePlaceholder: {
type: String,
default: ''
},
descriptionPlaceholder: {
type: String,
default: 'Any text you want that better describes this resource'
@ -65,15 +52,23 @@ export default {
},
data() {
const metadata = { ...this.value };
let metadata = this.value.metadata;
if ( !metadata ) {
metadata = {};
this.value.metadata = metadata;
}
if ( this.namespaced && !metadata.namespace ) {
metadata.namespace = this.$store.getters['defaultNamespace'];
}
const description = metadata.annotations?.[DESCRIPTION];
return {
namespace: metadata.namespace,
name: metadata.name,
description,
};
},
@ -83,21 +78,24 @@ export default {
},
detailTopColumns() {
const { metadata = {} } = this.value;
const { annotations = {} } = metadata;
return [
this.namespace
metadata.namespace
? {
title: 'Namespace',
content: this.namespace
content: metadata.namespace
} : null,
this.name
metadata.name
? {
title: 'Name',
content: this.name
content: metadata.name
} : null,
this.description
annotations[DESCRIPTION]
? {
title: 'Description',
content: this.description
content: annotations[DESCRIPTION]
} : null,
...this.extraDetailColumns
].filter(c => c);
@ -128,6 +126,20 @@ export default {
},
},
watch: {
name(val) {
this.value.metadata.name = val;
},
namespace(val) {
this.value.metadata.namespace = val;
},
description(val) {
this.value.setAnnotation(DESCRIPTION, val);
},
},
mounted() {
this.$nextTick(() => {
if (this.$refs.name) {
@ -140,22 +152,6 @@ export default {
changeNameAndNamespace(e) {
this.name = (e.text || '').toLowerCase();
this.namespace = e.selected;
this.$nextTick(() => {
this.update();
});
},
update() {
const out = {
...this.value,
name: this.name,
};
if (this.namespaced) {
out.namespace = this.namespace;
}
this.$emit('input', out);
}
}
};
@ -188,19 +184,17 @@ export default {
:disabled="nameDisabled"
:mode="mode"
:min-height="30"
@input="update"
/>
</slot>
</div>
<div :class="{col: true, [colSpan]: true}">
<LabeledInput
key="description"
:value="description"
v-model="description"
label="Description"
:mode="mode"
:placeholder="descriptionPlaceholder"
:min-height="30"
@input="e=>$emit('update:description', e)"
/>
</div>
<div v-for="slot in extraColumns" :key="slot" :class="{col: true, [colSpan]: true}">

View File

@ -14,7 +14,7 @@ export default {
return { typeDisplay: this.value.typeDisplay, serviceAccountLink: null };
}
return { typeDisplay: this.value };
return { typeDisplay: this.value, serviceAccountLink: null };
},
methods: {
async findServiceAccount() {

View File

@ -15,3 +15,33 @@ export const NODE_ROLES = {
WORKER: 'node-role.kubernetes.io/worker',
ETCD: 'node-role.kubernetes.io/etcd',
};
export const LABEL_PREFIX_TO_IGNORE = [
'io.cattle.lifecycle.',
'beta.kubernetes.io/',
'failure-domain.beta.kubernetes.io/',
'node-role.kubernetes.io/',
'kubernetes.io/',
'cattle.io/',
'authz.management.cattle.io',
'rke.cattle.io',
'field.cattle.io',
'workload.user.cattle.io/',
'k3s.io',
'node.kubernetes.io',
];
export const ANNOTATIONS_TO_IGNORE_CONTAINS = [
'coreos.com/',
'cattle.io/',
'k3s.io',
];
export const ANNOTATIONS_TO_IGNORE_PREFIX = [
'kubernetes.io/',
'beta.kubernetes.io/',
'node.alpha.kubernetes.io/',
'volumes.kubernetes.io/',
'k3s.io',
]
;

View File

@ -21,8 +21,7 @@ export default {
<template>
<form>
<NameNsDescription
v-model="value.metadata"
:description.sync="description"
:value="value"
:mode="mode"
name-label="Name"
:register-before-hook="registerBeforeHook"

View File

@ -72,8 +72,7 @@ export default {
<div>
<form>
<NameNsDescription
v-model="value.metadata"
:description.sync="description"
:value="value"
:namespaced="false"
:mode="mode"
:extra-columns="extraColumns"

View File

@ -179,7 +179,7 @@ export default {
<template>
<form>
<NameNsDescription v-model="metadata" :mode="mode" :description.sync="description" />
<NameNsDescription :value="value" :mode="mode" />
<div>
<h3>
Rules

View File

@ -34,11 +34,10 @@ export default {
<template>
<div class="node">
<NameNsDescription
v-model="value.metadata"
:value="value"
:namespaced="false"
:mode="mode"
name-label="Name"
:description.sync="description"
/>
<div class="row">
<Labels :spec="value" :mode="mode" :display-side-by-side="true" />

View File

@ -49,11 +49,10 @@ export default {
<template>
<form>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
name-label="Name"
:register-before-hook="registerBeforeHook"
:description.sync="description"
>
<template v-slot:namespace>
<LabeledInput

View File

@ -47,11 +47,10 @@ export default {
<template>
<form>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
name-label="Name"
:register-before-hook="registerBeforeHook"
:description.sync="description"
/>
<div class="spacer"></div>

View File

@ -72,11 +72,10 @@ export default {
</div>
<template v-else>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
name-label="Name"
:register-before-hook="registerBeforeHook"
:description.sync="description"
/>
<div class="spacer"></div>

View File

@ -65,11 +65,10 @@ export default {
<form>
<div class="row">
<NameNsDescription
v-model="value.metadata"
:value="value"
class="col span-12"
:mode="mode"
:register-before-hook="registerBeforeHook"
:description.sync="description"
/>
</div>
<h2>Rules</h2>

View File

@ -246,13 +246,12 @@ export default {
<template>
<div>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
:name-label="isSidecar ? 'Container Name' : 'Service Name'"
:extra-columns="extraColumns"
:namespaced="showNamespace"
:register-before-hook="registerBeforeHook"
:description.sync="description"
>
<template v-if="isSidecar" #name>
<LabeledInput

View File

@ -75,11 +75,10 @@ export default {
<div v-if="loading" />
<form v-else>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
name-label="Stack Name"
:register-before-hook="registerBeforeHook"
:description.sync="description"
/>
<div class="spacer"></div>

View File

@ -173,7 +173,7 @@ export default {
<template>
<form>
<NameNsDescription v-model="value.metadata" :description.sync="description" :mode="mode" :extra-columns="['type']">
<NameNsDescription :value="value" :mode="mode" :extra-columns="['type']">
<template v-slot:type>
<LabeledSelect
v-model="value._type"

View File

@ -280,7 +280,7 @@ export default {
<template>
<form>
<slot :value="value" name="top">
<NameNsDescription v-model="value.metadata" :mode="mode" :extra-columns="['type']" :description.sync="description">
<NameNsDescription :value="value" :mode="mode" :extra-columns="['type']">
<template v-slot:type>
<LabeledSelect v-model="type" label="Type" :disabled="isEdit" :options="workloadTypeOptions" />
</template>

View File

@ -1,7 +1,33 @@
import omitBy from 'lodash/omitBy';
import pickBy from 'lodash/pickBy';
import ChildHook, { BEFORE_SAVE_HOOKS, AFTER_SAVE_HOOKS } from './child-hook';
import { _CREATE, _EDIT, _VIEW } from '@/config/query-params';
import { LAST_NAMESPACE } from '@/store/prefs';
import { DESCRIPTION } from '@/config/labels-annotations';
import { DESCRIPTION, LABEL_PREFIX_TO_IGNORE, ANNOTATIONS_TO_IGNORE_CONTAINS, ANNOTATIONS_TO_IGNORE_PREFIX } from '@/config/labels-annotations';
// return true if the string starts with one of the values in prefixes array
const matchesSomePrefix = (string, prefixes) => {
for (const prefix of prefixes) {
const regex = new RegExp(`^${ prefix }`);
if (string.match(regex)) {
return true;
}
}
return false;
};
// return true if string includes at least one of the strings in matchStrings array
const containsSomeString = (string, matchStrings) => {
for (const matchString of matchStrings) {
if (string.includes(matchString)) {
return true;
}
}
return false;
};
export default {
mixins: [ChildHook],
@ -49,18 +75,22 @@ export default {
v.metadata = {};
}
// track description separately from the rest of annotations because it appears separately in UI
let description;
if ((v.metadata.annotations || {})[DESCRIPTION]) {
description = v.metadata.annotations[DESCRIPTION];
if (this.mode !== 'view') {
// remove description from annotations so it is not displayed/tracked in annotation component as well as NameNsDescription
delete v.metadata.annotations[DESCRIPTION];
}
if ( !v.metadata.annotations ) {
v.metadata.annotations = {};
}
return { errors: null, description };
if ( !v.metadata.labels ) {
v.metadata.labels = {};
}
// keep label and annotation filters in data so each resource CRUD page can alter individiaully
return {
errors: null,
labelPrefixToIgnore: LABEL_PREFIX_TO_IGNORE,
annotationsToIgnoreContains: ANNOTATIONS_TO_IGNORE_CONTAINS,
annotationsToIgnorePrefix: ANNOTATIONS_TO_IGNORE_PREFIX
};
},
computed: {
@ -82,19 +112,39 @@ export default {
labels: {
get() {
return this.value?.metadata?.labels || {};
const all = this.value?.metadata?.labels || {};
return omitBy(all, (value, key) => {
return matchesSomePrefix(key, this.labelPrefixToIgnore);
});
},
set(neu) {
this.$set(this.value.metadata, 'labels', neu);
const all = this.value?.metadata?.labels || {};
const wasIgnored = pickBy(all, (value, key) => {
return matchesSomePrefix(key, this.labelPrefixToIgnore);
});
this.$set(this.value.metadata, 'labels', { ...neu, ...wasIgnored });
}
},
annotations: {
get() {
return this.value?.metadata?.annotations || {};
const all = this.value?.metadata?.annotations || {};
return omitBy(all, (value, key) => {
return (matchesSomePrefix(key, this.annotationsToIgnorePrefix) || containsSomeString(key, this.annotationsToIgnoreContains));
});
},
set(neu) {
this.$set(this.value.metadata, 'annotations', neu);
const all = this.value?.metadata?.annotations || {};
const wasIgnored = pickBy(all, (value, key) => {
return (matchesSomePrefix(key, this.annotationsToIgnorePrefix) || containsSomeString(key, this.annotationsToIgnoreContains));
});
this.$set(this.value.metadata, 'annotations', { ...neu, ...wasIgnored });
}
}

View File

@ -102,11 +102,10 @@ export default {
v-if="editAsYaml"
>
<NameNsDescription
v-model="localValue.metadata"
:value="value"
:mode="mode"
:namespaced="false"
:extra-columns="['template']"
:description.sync="description"
>
<template v-slot:template>
<LabeledSelect

View File

@ -185,12 +185,11 @@ export default {
<div v-if="value.save" class="gatekeeper-constraint">
<div>
<NameNsDescription
v-model="value.metadata"
:value="value"
:mode="mode"
:namespaced="false"
:extra-columns="['template']"
:extra-detail-columns="extraDetailColumns"
:description.sync="description"
>
<template v-slot:template>
<LabeledSelect