Recent types, Import yaml

This commit is contained in:
Vincent Fiduccia 2020-03-20 03:13:59 -07:00
parent 518f11e654
commit 79bdbc263b
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
9 changed files with 183 additions and 102 deletions

View File

@ -7,7 +7,6 @@ export default {
computed: { computed: {
value: { value: {
get() { get() {
console.log('Get Value');
const options = this.options; const options = this.options;
const existing = findBy(options, 'id', this.$store.getters['clusterId']); const existing = findBy(options, 'id', this.$store.getters['clusterId']);
@ -24,8 +23,6 @@ export default {
}, },
options() { options() {
console.log('Get Options');
const all = this.$store.getters['management/all'](MANAGEMENT.CLUSTER); const all = this.$store.getters['management/all'](MANAGEMENT.CLUSTER);
const out = all.map((x) => { const out = all.map((x) => {
return { return {

View File

@ -1,5 +1,5 @@
import { import {
CONFIG_MAP, GATEKEEPER_CONSTRAINT_TEMPLATE, NAMESPACE, NODE, SECRET, RIO, RBAC, INGRESS, WORKLOAD CONFIG_MAP, GATEKEEPER_CONSTRAINT_TEMPLATE, NAMESPACE, NODE, SECRET, RIO, RBAC, INGRESS
} from '@/config/types'; } from '@/config/types';
import { import {
@ -41,7 +41,10 @@ export default function(store) {
basicType([ basicType([
NAMESPACE, NAMESPACE,
NODE, NODE,
WORKLOAD, 'workloads',
'gatekeeper',
'gatekeeper-constraints',
'gatekeeper-templates',
]); ]);
mapTypeToComponentName(/^constraints.gatekeeper.sh.*$/, 'gatekeeper-constraint'); mapTypeToComponentName(/^constraints.gatekeeper.sh.*$/, 'gatekeeper-constraint');
@ -52,7 +55,7 @@ export default function(store) {
mapType('endpoints', 'Endpoint'); // Bad plural mapType('endpoints', 'Endpoint'); // Bad plural
// Move some core things into Cluster // Move some core things into Cluster
moveType(/^(namespace|node|persistentvolume)$/, 'Cluster'); moveType(/^(namespace|node)$/, 'Cluster');
weightGroup('Cluster', 99); weightGroup('Cluster', 99);
weightGroup('Core', 98); weightGroup('Core', 98);
@ -195,6 +198,7 @@ export default function(store) {
namespaced: true, namespaced: true,
name: 'workloads', name: 'workloads',
group: 'Cluster', group: 'Cluster',
weight: 10,
route: { route: {
name: 'c-cluster-workloads', name: 'c-cluster-workloads',
params: { resource: 'workload' } params: { resource: 'workload' }

View File

@ -2,11 +2,13 @@
import ResourceYaml from '@/components/ResourceYaml'; import ResourceYaml from '@/components/ResourceYaml';
import { createYaml } from '@/utils/create-yaml'; import { createYaml } from '@/utils/create-yaml';
import { SCHEMA } from '@/config/types'; import { SCHEMA } from '@/config/types';
import { EDIT_YAML, _FLAGGED } from '@/config/query-params';
export default { export default {
components: { ResourceYaml }, components: { ResourceYaml },
data() { data() {
if (this.hasComponent) { if (this.hasCustomEdit) {
this.$store.getters['type-map/importEdit'](this.resource)().then((component) => { this.$store.getters['type-map/importEdit'](this.resource)().then((component) => {
this.importedEditComponent = component.default; this.importedEditComponent = component.default;
}); });
@ -14,6 +16,7 @@ export default {
return { importedEditComponent: null }; return { importedEditComponent: null };
}, },
computed: { computed: {
doneRoute() { doneRoute() {
const name = this.$route.name.replace(/-create$/, ''); const name = this.$route.name.replace(/-create$/, '');
@ -21,10 +24,6 @@ export default {
return name; return name;
}, },
hasComponent() {
return this.$store.getters['type-map/hasCustomEdit'](this.resource);
},
showComponent() { showComponent() {
return this.$store.getters['type-map/importEdit'](this.resource); return this.$store.getters['type-map/importEdit'](this.resource);
}, },
@ -47,27 +46,40 @@ export default {
return out; return out;
}, },
}, },
async asyncData(ctx) { async asyncData(ctx) {
const { route, store } = ctx;
const { resource, namespace } = ctx.params; const { resource, namespace } = ctx.params;
const schemas = ctx.store.getters['cluster/all'](SCHEMA); const schemas = store.getters['cluster/all'](SCHEMA);
const schema = ctx.store.getters['cluster/schemaFor'](resource); const schema = store.getters['cluster/schemaFor'](resource);
const data = { type: resource }; const data = { type: resource };
if ( schema.attributes.namespaced ) { if ( schema.attributes.namespaced ) {
data.metadata = { namespace }; data.metadata = { namespace };
} }
const model = await ctx.store.dispatch('cluster/create', data);
const model = await store.dispatch('cluster/create', data);
const yaml = createYaml(schemas, resource, data); const yaml = createYaml(schemas, resource, data);
const hasCustomEdit = store.getters['type-map/hasCustomEdit'](resource);
const asYaml = (route.query[EDIT_YAML] === _FLAGGED) || !hasCustomEdit;
return { return {
resource, model, yaml, schema schema,
resource,
model,
yaml,
asYaml,
hasCustomEdit
}; };
} }
}; };
</script> </script>
<template> <template>
<div v-if="hasComponent"> <ResourceYaml v-if="asYaml" :obj="model" :value="yaml" :done-route="doneRoute" :for-create="true" />
<div v-else>
<header> <header>
<h1> <h1>
Create <nuxt-link :to="parentLink"> Create <nuxt-link :to="parentLink">
@ -85,5 +97,4 @@ export default {
:done-override="doneEditOverride" :done-override="doneEditOverride"
/> />
</div> </div>
<ResourceYaml v-else :obj="model" :value="yaml" :done-route="doneRoute" :for-create="true" />
</template> </template>

View File

@ -12,7 +12,21 @@ export default {
listComponent = this.$store.getters['type-map/importList'](this.resource); listComponent = this.$store.getters['type-map/importList'](this.resource);
} }
const params = { ...this.$route.params };
const formRoute = this.$router.resolve({ name: `${ this.$route.name }-create`, params }).href;
const query = { [EDIT_YAML]: _FLAGGED };
const yamlRoute = this.$router.resolve({
name: `${ this.$route.name }-create`,
params,
query
}).href;
return { return {
formRoute,
yamlRoute,
listComponent, listComponent,
EDIT_YAML, EDIT_YAML,
FLAGGED: _FLAGGED FLAGGED: _FLAGGED
@ -62,13 +76,17 @@ export default {
{{ typeDisplay }} {{ typeDisplay }}
</h1> </h1>
<div class="actions"> <div class="actions">
<nuxt-link :to="{path: 'create', params: {'as-yaml': null}}" append tag="button" type="button" class="btn bg-primary"> <nuxt-link
:to="{path: yamlRoute}"
tag="button"
type="button"
class="btn bg-primary"
>
Import Import
</nuxt-link> </nuxt-link>
<nuxt-link <nuxt-link
v-if="hasEditComponent" v-if="hasEditComponent"
to="create" :to="{path: formRoute}"
append
tag="button" tag="button"
type="button" type="button"
class="btn bg-primary" class="btn bg-primary"

View File

@ -9,6 +9,8 @@ export default {
data(ctx) { data(ctx) {
const createUrl = this.$router.resolve({ name: 'c-cluster-gatekeeper-constraints-create', params: this.$route.params }).href; const createUrl = this.$router.resolve({ name: 'c-cluster-gatekeeper-constraints-create', params: this.$route.params }).href;
this.$store.dispatch('type-map/addRecent', 'gatekeeper-constraints');
return { return {
headers: [ headers: [
STATE, STATE,

View File

@ -108,7 +108,9 @@ export default {
}); });
} }
await store.dispatch('type-map/addRecent', 'workload'); // Don't add to recent for now, it doesn't handle the parent of nested types well
// and it's always at the top anyway.
// await store.dispatch('type-map/addRecent', 'gatekeeper');
return { return {
gatekeeperEnabled: !!gatekeeper?.id, gatekeeperEnabled: !!gatekeeper?.id,

View File

@ -12,6 +12,8 @@ export default {
}; };
const createUrl = this.$router.resolve({ name: 'c-cluster-resource-create', params }).href; const createUrl = this.$router.resolve({ name: 'c-cluster-resource-create', params }).href;
this.$store.dispatch('type-map/addRecent', 'gatekeeper-templates');
return { return {
headers: [ headers: [
STATE, STATE,

View File

@ -59,7 +59,7 @@ export default {
return all; return all;
}, []); }, []);
await store.dispatch('type-map/addRecent', 'workload'); await store.dispatch('type-map/addRecent', 'workloads');
return { resources }; return { resources };
}, },

View File

@ -10,7 +10,6 @@
// isBasic(schema) Returns true if this type should be included in basic view // isBasic(schema) Returns true if this type should be included in basic view
// typeWeightFor(type) Get the weight value for a particular type label // typeWeightFor(type) Get the weight value for a particular type label
// groupWeightFor(group) Get the weight value for a particular group // groupWeightFor(group) Get the weight value for a particular group
// virtualTypes() Returns a list of the virtual pages to add to the treee
// headersFor(schema) Returns the column definitions for a type to give to SortableTable // headersFor(schema) Returns the column definitions for a type to give to SortableTable
// //
// 2) Detecting and usign custom list/detail/edit/header components // 2) Detecting and usign custom list/detail/edit/header components
@ -78,6 +77,7 @@ import { escapeRegex, ucFirst, escapeHtml } from '@/utils/string';
import { SCHEMA, COUNT } from '@/config/types'; import { SCHEMA, COUNT } from '@/config/types';
import { STATE, NAMESPACE_NAME, NAME, AGE } from '@/config/table-headers'; import { STATE, NAMESPACE_NAME, NAME, AGE } from '@/config/table-headers';
import { FAVORITE_TYPES, RECENT_TYPES, EXPANDED_GROUPS } from '@/store/prefs'; import { FAVORITE_TYPES, RECENT_TYPES, EXPANDED_GROUPS } from '@/store/prefs';
import { normalizeType } from '@/plugins/steve/normalize';
export function DSL(store, module = 'type-map') { export function DSL(store, module = 'type-map') {
return { return {
@ -202,8 +202,21 @@ export const getters = {
return (schemaOrName) => { return (schemaOrName) => {
let group = schemaOrName; let group = schemaOrName;
if ( typeof group === 'object' ) { if ( typeof schemaOrName === 'object' ) {
group = _applyMapping(group, state.typeMoveMappings, 'attributes.group', state.cache.typeMove); let moved = false;
for ( const rule of state.typeMoveMappings ) {
const re = stringToRegex(rule.match);
if ( schemaOrName.id.match(re) ) {
moved = true;
group = rule.replace;
}
}
if ( !moved ) {
group = group.attributes.group;
}
} }
return _applyMapping(group, state.groupMappings, null, state.cache.groupLabel, (group) => { return _applyMapping(group, state.groupMappings, null, state.cache.groupLabel, (group) => {
@ -219,20 +232,27 @@ export const getters = {
}, },
isBasic(state) { isBasic(state) {
return (schema) => { return (schemaId) => {
return state.basicTypes[schema.id] || false; return state.basicTypes[schemaId] || false;
}; };
}, },
isFavorite(state, getters, rootState, rootGetters) { isFavorite(state, getters, rootState, rootGetters) {
return (schema) => { return (schemaId) => {
return rootGetters['prefs/get'](FAVORITE_TYPES).includes(schema.id) || false; return rootGetters['prefs/get'](FAVORITE_TYPES).includes(schemaId) || false;
}; };
}, },
isRecent(state, getters, rootState, rootGetters) { recentWeight(state, getters, rootState, rootGetters) {
return (schema) => { return (schemaId) => {
return rootGetters['prefs/get'](RECENT_TYPES).includes(schema.id) || false; const recents = rootGetters['prefs/get'](RECENT_TYPES);
const idx = recents.indexOf(schemaId);
if ( idx === -1 ) {
return idx;
}
return recents.length - idx;
}; };
}, },
@ -250,6 +270,7 @@ export const getters = {
getTree(state, getters, rootState, rootGetters) { getTree(state, getters, rootState, rootGetters) {
return (mode, allTypes, clusterId, namespaces, currentType, search) => { return (mode, allTypes, clusterId, namespaces, currentType, search) => {
// modes: basic, used, all, recent, favorite
// null namespaces means all, otherwise it will be an array of namespaces to include // null namespaces means all, otherwise it will be an array of namespaces to include
let searchRegex; let searchRegex;
@ -263,7 +284,7 @@ export const getters = {
for ( const type in allTypes ) { for ( const type in allTypes ) {
const typeObj = allTypes[type]; const typeObj = allTypes[type];
if ( getters.isIgnored(typeObj.schema) ) { if ( typeObj.schema && getters.isIgnored(typeObj.schema) ) {
// Skip ignored groups & types // Skip ignored groups & types
continue; continue;
} }
@ -273,7 +294,7 @@ export const getters = {
if ( typeObj.id === currentType ) { if ( typeObj.id === currentType ) {
// If this is the type currently being shown, always show it // If this is the type currently being shown, always show it
} else if ( mode === 'basic' && !getters.isBasic(typeObj.schema) ) { } else if ( mode === 'basic' && !getters.isBasic(typeObj.name) ) {
// If we want the basic tree only return basic types; // If we want the basic tree only return basic types;
continue; continue;
} else if ( count === 0 && mode === 'used') { } else if ( count === 0 && mode === 'used') {
@ -281,7 +302,7 @@ export const getters = {
continue; continue;
} }
const label = getters.singularLabelFor(typeObj.schema); const label = typeObj.label;
const labelDisplay = highlightLabel(label, namespaced); const labelDisplay = highlightLabel(label, namespaced);
if ( !labelDisplay ) { if ( !labelDisplay ) {
@ -292,13 +313,38 @@ export const getters = {
let group; let group;
if ( mode === 'basic' ) { if ( mode === 'basic' ) {
group = _ensureGroup(root, 'Cluster'); if ( typeObj.group && typeObj.group.includes('::') ) {
group = _ensureGroup(root, typeObj.group);
} else {
group = _ensureGroup(root, 'Cluster');
}
} else if ( mode === 'recent' ) { } else if ( mode === 'recent' ) {
group = _ensureGroup(root, 'Recent'); group = _ensureGroup(root, 'Recent');
} else if ( mode === 'favorite' ) { } else if ( mode === 'favorite' ) {
group = _ensureGroup(root, 'Favorite'); group = _ensureGroup(root, 'Favorite');
} else { } else {
group = _ensureGroup(root, typeObj.schema); group = _ensureGroup(root, typeObj.schema || typeObj.group );
}
let route = typeObj.route;
// Make the default route if one isn't set
if (!route ) {
route = {
name: 'c-cluster-resource',
params: {
cluster: clusterId,
resource: typeObj.name,
}
};
typeObj.route = route;
}
// Cluster ID should always be set
if ( route && typeof route === 'object' ) {
route.params = route.params || {};
route.params.cluster = clusterId;
} }
group.children.push({ group.children.push({
@ -306,48 +352,14 @@ export const getters = {
labelDisplay, labelDisplay,
count, count,
namespaced, namespaced,
name: typeObj.id, route,
weight: getters.typeWeightFor(label), name: typeObj.name,
route: { weight: typeObj.weight || getters.typeWeightFor(label),
name: 'c-cluster-resource',
params: {
cluster: clusterId,
resource: typeObj.id,
}
},
}); });
} }
// Add virtual types
if ( mode === 'basic' || mode === 'all' ) {
const virt = getters.virtualTypes();
for ( const vt of virt ) {
const item = clone(vt);
const namespaced = item.namespaced;
if ( item.route && typeof item.route === 'object' ) {
item.route.params = item.route.params || {};
item.route.params.cluster = clusterId;
}
const labelDisplay = highlightLabel(item.label, namespaced);
if ( !labelDisplay ) {
// Search happens in highlight and retuns null if not found
continue;
}
item.labelDisplay = labelDisplay;
const group = _ensureGroup(root, item.group, item.route);
group.children.push(item);
}
}
// Recursively sort the groups // Recursively sort the groups
_sortGroup(root); _sortGroup(root, mode);
return root.children; return root.children;
@ -415,48 +427,76 @@ export const getters = {
for ( const schema of schemas ) { for ( const schema of schemas ) {
const attrs = schema.attributes || {}; const attrs = schema.attributes || {};
const count = counts[schema.id]; const count = counts[schema.id];
const groupName = attrs.group || 'core'; let weight = null;
let recentWeight = null;
if ( !attrs.kind ) { if ( !attrs.kind ) {
// Skip the "apiGroups" resource which has no kind // Skip the "apiGroups" resource which has no kind
continue; continue;
} else if ( mode === 'basic' && !getters.isBasic(schema) ) { } else if ( mode === 'basic' && !getters.isBasic(schema.id) ) {
continue; continue;
} else if ( mode === 'favorite' && !getters.isFavorite(schema) ) { } else if ( mode === 'favorite' && !getters.isFavorite(schema.id) ) {
continue;
} else if ( mode === 'recent' && !getters.isRecent(schema) ) {
continue; continue;
} else if ( mode === 'recent' ) {
weight = getters.recentWeight(schema.id);
recentWeight = weight;
if ( weight < 0 ) {
continue;
}
} }
out[schema.id] = { out[schema.id] = {
schema, schema,
mode, mode,
group: groupName, weight,
id: schema.id, recentWeight,
name: schema.id,
label: getters.singularLabelFor(schema), label: getters.singularLabelFor(schema),
namespaced: attrs.namespaced, namespaced: attrs.namespaced,
count: count ? count.summary.count : null, count: count ? count.summary.count || 0 : null,
byNamespace: count ? count.namespaces : {}, byNamespace: count ? count.namespaces : {},
revision: count ? count.revision : null, revision: count ? count.revision : null,
}; };
} }
return out; // Add virtual types
};
},
virtualTypes(state, getters, rootState, rootGetters) {
return () => {
const isRancher = rootGetters.isRancher; const isRancher = rootGetters.isRancher;
const allTypes = getters.allTypes() || {};
const out = state.virtualTypes.filter((typeObj) => { for ( const vt of state.virtualTypes ) {
if ( typeObj.ifIsRancher && !isRancher ) { const item = clone(vt);
return false; const id = item.name;
let weight = null;
let recentWeight = null;
if ( item.ifIsRancher && !isRancher ) {
continue;
} }
return !typeObj.ifHaveType || !!allTypes[typeObj.ifHaveType]; if ( item.ifHaveType && !findBy(schemas, 'id', normalizeType(item.ifHaveType)) ) {
}); continue;
}
if ( mode === 'basic' && !getters.isBasic(id) ) {
continue;
} else if ( mode === 'favorite' && !getters.isFavorite(id) ) {
continue;
} else if ( mode === 'recent' ) {
weight = getters.recentWeight(id);
recentWeight = weight;
if ( weight < 0 ) {
continue;
}
}
item.mode = mode;
item.weight = weight;
item.recentWeight = recentWeight;
item.label = item.label || item.name;
out[id] = item;
}
return out; return out;
}; };
@ -781,7 +821,6 @@ export const mutations = {
export const actions = { export const actions = {
addRecent({ commit, rootGetters }, type) { addRecent({ commit, rootGetters }, type) {
/*
const types = rootGetters['prefs/get'](RECENT_TYPES) || []; const types = rootGetters['prefs/get'](RECENT_TYPES) || [];
removeObject(types, type); removeObject(types, type);
@ -792,7 +831,6 @@ export const actions = {
} }
commit('prefs/set', { key: RECENT_TYPES, val: types }, { root: true }); commit('prefs/set', { key: RECENT_TYPES, val: types }, { root: true });
*/
}, },
addFavorite({ commit, rootGetters }, type) { addFavorite({ commit, rootGetters }, type) {
@ -824,19 +862,26 @@ export const actions = {
}, },
}; };
function _sortGroup(tree) { function _sortGroup(tree, mode) {
tree.children = sortBy(tree.children, ['namespaced', 'weight:desc', 'label']); const by = ['namespaced', 'weight:desc', 'label'];
if ( mode === 'recent' ) {
removeObject(by, 'namespaced');
}
tree.children = sortBy(tree.children, by);
for (const entry of tree.children ) { for (const entry of tree.children ) {
if ( entry.children ) { if ( entry.children ) {
_sortGroup(entry); _sortGroup(entry, mode);
} }
} }
} }
function _matchingCounts(typeObj, namespaces) { function _matchingCounts(typeObj, namespaces) {
// That was easy // That was easy
if ( !typeObj.namespaced || !typeObj.byNamespace || namespaces === null ) { if ( !typeObj.namespaced || !typeObj.byNamespace || namespaces === null || typeObj.count === null) {
return typeObj.count || 0; return typeObj.count;
} }
let out = 0; let out = 0;