Merge pull request #528 from codyrancher/ingress

Fixing up ingress pages
This commit is contained in:
Vincent Fiduccia 2020-04-21 14:10:37 -07:00 committed by GitHub
commit f7aa3d29a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 232 additions and 164 deletions

View File

@ -118,13 +118,13 @@ export default {
border-left: 0; border-left: 0;
margin-left: -1px; margin-left: -1px;
} }
}
.in-input { .in-input {
margin-right: 0; margin-right: 0;
border-radius: var(--border-radius) 0 0 var(--border-radius); border-radius: var(--border-radius) 0 0 var(--border-radius);
& .v-select{ &.v-select {
height: 100%; height: initial;
.vs__selected { .vs__selected {
margin: 0; margin: 0;
@ -184,6 +184,7 @@ export default {
transform: rotate(180deg) scale(0.75); transform: rotate(180deg) scale(0.75);
} }
} }
}
} }
</style> </style>

View File

@ -103,7 +103,6 @@ export default {
</script> </script>
<template> <template>
<div>
<div v-if="isView"> <div v-if="isView">
<div :class="{'labeled-input': true, raised, focused, empty, [mode]: true}"> <div :class="{'labeled-input': true, raised, focused, empty, [mode]: true}">
<label> <label>
@ -154,7 +153,6 @@ export default {
</div> </div>
</template> </template>
</v-select> </v-select>
</div>
</template> </template>
<style lang='scss'> <style lang='scss'>

View File

@ -15,7 +15,7 @@ export default {
} }
}, },
data() { data() {
const serviceName = this.value?.http?.paths[0]?.backend?.serviceName; const serviceName = this.value?.rules?.[0].http?.paths[0]?.backend?.serviceName || this.value?.backend?.serviceName || '';
const targetsWorkload = !serviceName.startsWith('ingress-'); const targetsWorkload = !serviceName.startsWith('ingress-');
let name; let params; let name; let params;
@ -34,16 +34,37 @@ export default {
return { return {
name, params, targetsWorkload name, params, targetsWorkload
}; };
},
computed: {
showHost() {
return !!this.host;
},
host() {
return this.value?.rules?.[0].host;
},
pathServiceName() {
return this.value?.rules?.[0]?.http?.paths?.[0]?.backend?.serviceName;
},
backendServiceName() {
return this.value?.backend?.serviceName;
}
} }
}; };
</script> </script>
<template> <template>
<div> <div v-if="value">
<a rel="nofollow noopener noreferrer" target="_blank" :href="'http://'+value.host">{{ value.host }}</a> <div v-if="pathServiceName">
<i class="icon icon-chevron-right" /> <a v-if="showHost" rel="nofollow noopener noreferrer" target="_blank" :href="'http://' + host">{{ host }}</a>
<i v-if="showHost" class="icon icon-chevron-right" />
<nuxt-link :to="{name, params}"> <nuxt-link :to="{name, params}">
{{ value.http.paths[0].backend.serviceName }} {{ pathServiceName }}
</nuxt-link> </nuxt-link>
</div> </div>
<div v-else-if="backendServiceName">
<nuxt-link :to="{name, params}">
{{ backendServiceName }}
</nuxt-link>
</div>
</div>
</template> </template>

View File

@ -392,8 +392,7 @@ export const API_GROUP = {
export const INGRESS_TARGET = { export const INGRESS_TARGET = {
name: 'ingressTarget', name: 'ingressTarget',
label: 'Target', label: 'Target',
value: "$['spec']['rules'][0]", value: "$['spec']",
formatter: 'IngressTarget', formatter: 'IngressTarget',
sort: "$['spec']['rules'][0].host", sort: "$['spec']['rules'][0].host",
} };
;

View File

@ -5,7 +5,7 @@ import DetailTop from '@/components/DetailTop';
import SortableTable from '@/components/SortableTable'; import SortableTable from '@/components/SortableTable';
import Tabbed from '@/components/Tabbed'; import Tabbed from '@/components/Tabbed';
import Tab from '@/components/Tabbed/Tab'; import Tab from '@/components/Tabbed/Tab';
import KVTable from '@/components/KVTable'; import Labels from '@/components/form/Labels';
export default { export default {
components: { components: {
@ -13,7 +13,7 @@ export default {
SortableTable, SortableTable,
Tabbed, Tabbed,
Tab, Tab,
KVTable Labels
}, },
mixins: [CreateEditView], mixins: [CreateEditView],
props: { props: {
@ -28,8 +28,8 @@ export default {
computed: { computed: {
detailTopColumns() { detailTopColumns() {
const firstRule = this.value?.spec?.rules[0] || {}; const firstRule = this.firstRule || {};
const firstPath = firstRule?.http?.paths[0] || {}; const firstPath = firstRule?.http?.paths?.[0] || {};
const columns = [ const columns = [
{ {
@ -75,6 +75,22 @@ export default {
]; ];
}, },
backendHeaders() {
return [
{
name: 'target',
label: 'Target',
value: 'serviceName',
width: 200
},
{
name: 'port',
label: 'Port',
value: 'servicePort'
}
];
},
certHeaders() { certHeaders() {
return [ return [
{ {
@ -113,6 +129,14 @@ export default {
return cert; return cert;
}); });
}, },
firstRule() {
return this.value?.spec?.rules?.[0];
},
ruleRows() {
return this.withUrl(this.firstRule?.http?.paths || []);
}
}, },
methods: { methods: {
@ -150,18 +174,19 @@ export default {
<template> <template>
<div> <div>
<DetailTop :columns="detailTopColumns" /> <DetailTop class="mb-20" :columns="detailTopColumns" />
<div> <div>
<h3 class="mb-20"> <h3 class="mb-20">
Rules Rules
</h3> </h3>
<div v-if="value.spec.rules">
<div v-for="(rule, i) in value.spec.rules" :key="i" class="rule mb-20"> <div v-for="(rule, i) in value.spec.rules" :key="i" class="rule mb-20">
<div class="label-col mb-40"> <div class="label-col mb-40">
<span>Hostname</span> <span>Hostname</span>
<code> {{ rule.host }}</code> <code> {{ rule.host }}</code>
</div> </div>
<SortableTable <SortableTable
:rows="withUrl(rule.http.paths)" :rows="ruleRows"
:headers="ruleHeaders" :headers="ruleHeaders"
key-field="path" key-field="path"
:search="false" :search="false"
@ -170,9 +195,23 @@ export default {
/> />
</div> </div>
</div> </div>
<div v-else class="rule">
<div class="mb-10">
Use as the default backend
</div>
<SortableTable
:rows="[value.spec.backend]"
:headers="backendHeaders"
key-field="service"
:search="false"
:table-actions="false"
:row-actions="false"
/>
</div>
</div>
<Tabbed default-tab="labels"> <Tabbed default-tab="labels">
<Tab name="labels" label="Labels"> <Tab name="labels" label="Labels">
<KVTable :rows="value.metadata.labels" /> <Labels :spec="value" :mode="mode" />
</Tab> </Tab>
<Tab name="certificates" label="Certificates"> <Tab name="certificates" label="Certificates">
<SortableTable <SortableTable

View File

@ -29,7 +29,7 @@ export default {
const { paths = [{ id: random32(1) }] } = http; const { paths = [{ id: random32(1) }] } = http;
return { return {
host, paths, ruleMode: 'setHost' host, paths, ruleMode: this.value.asDefault ? 'asDefault' : 'setHost'
}; };
}, },
@ -93,7 +93,7 @@ export default {
@remove="e=>removePath(i)" @remove="e=>removePath(i)"
/> />
</template> </template>
<button :style="{'padding':'0px 0px 0px 5px'}" class="btn btn-sm role-link" @click="addPath"> <button v-if="ruleMode === 'setHost'" :style="{'padding':'0px 0px 0px 5px'}" class="btn btn-sm role-link" @click="addPath">
add path add path
</button> </button>
</div> </div>

View File

@ -1,8 +1,6 @@
<script> <script>
import Certificate from './Certificate'; import Certificate from './Certificate';
import Rule from './Rule'; import Rule from './Rule';
import { clone } from '@/utils/object';
import { allHash } from '@/utils/promise'; import { allHash } from '@/utils/promise';
import { SECRET, TLS_CERT, WORKLOAD_TYPES } from '@/config/types'; import { SECRET, TLS_CERT, WORKLOAD_TYPES } from '@/config/types';
import NameNsDescription from '@/components/form/NameNsDescription'; import NameNsDescription from '@/components/form/NameNsDescription';
@ -43,18 +41,7 @@ export default {
}, },
data() { data() {
const { metadata = {}, spec = {} } = clone(this.value); return { allSecrets: [], allWorkloads: [] };
if (!spec.rules) {
spec.rules = [{}];
}
if (!spec.tls) {
spec.tls = [{ }];
}
return {
metadata, spec, allSecrets: [], allWorkloads: []
};
}, },
computed: { computed: {
@ -75,6 +62,31 @@ export default {
}, },
}, },
created() {
if (!this.value.spec) {
this.value.spec = {};
}
if (!this.value.spec.rules) {
this.value.spec.rules = [{}];
}
if (this.value.spec.backend) {
if (!this.value.spec.rules[0].http) {
this.value.spec.rules[0].http = { paths: [] };
}
this.value.spec.rules[0].http.paths.push({ backend: this.value.spec.backend });
this.value.spec.rules[0].asDefault = true;
}
if (!this.value.spec.tls) {
this.value.spec.tls = [{ }];
}
this.registerBeforeHook(this.willSave, 'willSave');
},
methods: { methods: {
async loadDeps() { async loadDeps() {
const hash = await allHash({ const hash = await allHash({
@ -99,30 +111,30 @@ export default {
}, },
addRule() { addRule() {
this.spec.rules = [...this.spec.rules, {}]; this.value.spec.rules = [...this.value.spec.rules, {}];
}, },
removeRule(idx) { removeRule(idx) {
const neu = [...this.spec.rules]; const neu = [...this.value.spec.rules];
neu.splice(idx, 1); neu.splice(idx, 1);
this.$set(this.spec, 'rules', neu); this.$set(this.value.spec, 'rules', neu);
}, },
updateRule(neu, idx) { updateRule(neu, idx) {
this.$set(this.spec.rules, idx, neu); this.$set(this.value.spec.rules, idx, neu);
}, },
addCert() { addCert() {
this.spec.tls = [...this.spec.tls, {}]; this.value.spec.tls = [...this.value.spec.tls, {}];
}, },
removeCert(idx) { removeCert(idx) {
const neu = [...this.spec.tls]; const neu = [...this.value.spec.tls];
neu.splice(idx, 1); neu.splice(idx, 1);
this.$set(this.spec, 'tls', neu); this.$set(this.value.spec, 'tls', neu);
}, },
// filter a given list of resources by currently selected namespaces // filter a given list of resources by currently selected namespaces
@ -149,38 +161,31 @@ export default {
}); });
}, },
saveIngress(cb) { willSave() {
const defaultRule = this.spec.rules.filter(rule => rule.asDefault)[0]; const defaultRule = this.value.spec.rules.filter(rule => rule.asDefault)[0];
const nonDefaultRules = this.spec.rules.filter(rule => !rule.asDefault);
const defaultBackend = defaultRule?.http?.paths[0]?.backend; const defaultBackend = defaultRule?.http?.paths[0]?.backend;
const nonDefaultRules = this.value.spec.rules.filter(rule => !rule.asDefault);
nonDefaultRules.forEach(rule => delete rule.asDefault); nonDefaultRules.forEach(rule => delete rule.asDefault);
this.value.spec.rules = nonDefaultRules;
if (defaultBackend ) { if (defaultBackend ) {
this.$set(this.spec, 'backend', defaultBackend); this.$set(this.value.spec, 'backend', defaultBackend);
}
this.spec.rules = nonDefaultRules;
this.$set(this.value, 'spec', this.spec);
this.$set(this.value, 'metadata', this.metadata);
const saveUrl = this.value.urlFromAttrs;
this.save(cb, saveUrl);
} }
},
} }
}; };
</script> </script>
<template> <template>
<form> <form>
<NameNsDescription :value="{metadata}" :mode="mode" @input="e=>metadata=e" /> <NameNsDescription v-model="value" :mode="mode" @input="e=>metadata=e" />
<div> <div>
<h3> <h3>
Rules Rules
</h3> </h3>
<Rule <Rule
v-for="(rule, i) in spec.rules" v-for="(rule, i) in value.spec.rules"
:key="i" :key="i"
:value="rule" :value="rule"
:workloads="workloads" :workloads="workloads"
@ -194,15 +199,15 @@ export default {
<div> <div>
<Tabbed :default-tab="'labels'"> <Tabbed :default-tab="'labels'">
<Tab name="labels" label="Labels"> <Tab name="labels" label="Labels">
<Labels :spec="{metadata:{}}" mode="create" /> <Labels :spec="value" mode="create" />
</Tab> </Tab>
<Tab label="Certificates" name="certificates"> <Tab label="Certificates" name="certificates">
<Certificate <Certificate
v-for="(cert,i) in spec.tls" v-for="(cert,i) in value.spec.tls"
:key="i" :key="i"
:certs="certificates" :certs="certificates"
:value="cert" :value="cert"
@input="e=>$set(spec.tls, i, e)" @input="e=>$set(value.spec.tls, i, e)"
@remove="e=>removeCert(i)" @remove="e=>removeCert(i)"
/> />
<button class="btn btn-sm role-primary mt-20 " type="button" @click="addCert"> <button class="btn btn-sm role-primary mt-20 " type="button" @click="addCert">
@ -211,6 +216,6 @@ export default {
</Tab> </Tab>
</Tabbed> </Tabbed>
</div> </div>
<Footer :errors="errors" :mode="mode" @save="saveIngress" @done="done" /> <Footer :errors="errors" :mode="mode" @save="save" @done="done" />
</form> </form>
</template> </template>

View File

@ -774,7 +774,12 @@ export default {
const { metadata:{ namespace = 'default' } } = this; const { metadata:{ namespace = 'default' } } = this;
let url = schema.links.collection; let url = schema.links.collection;
const [group, resource] = schema?.attributes; const attributes = schema?.attributes;
if (!attributes) {
throw new Error('Attributes must be present on the schema');
}
const { group, resource } = attributes;
url = `${ url.slice(0, url.indexOf('/v1')) }/apis/${ group }/namespaces/${ namespace }/${ resource }`; url = `${ url.slice(0, url.indexOf('/v1')) }/apis/${ group }/namespaces/${ namespace }/${ resource }`;