dashboard/edit/rio.cattle.io.service/index.vue

275 lines
7.0 KiB
Vue

<script>
import Labels from '@/components/form/Labels';
import Networking from '@/edit/rio.cattle.io.service//Networking';
import Command from '@/edit/rio.cattle.io.service/Command';
import HealthCheck from '@/components/form/HealthCheck';
import { get } from '@/utils/object';
import { CONFIG_MAP, SECRET, RIO } from '@/config/types';
import Loading from '@/components/Loading';
import Tab from '@/components/Tabbed/Tab';
import Tabbed from '@/components/Tabbed';
import CreateEditView from '@/mixins/create-edit-view';
import { _EDIT, EDIT_CONTAINER, DEMO } from '@/config/query-params';
import Footer from '@/components/form/Footer';
import { findBy, filterBy, removeObject } from '@/utils/array';
import { allHash } from '@/utils/promise';
import DEMOS from '@/config/demos';
import Volumes from './Volumes';
import Upgrading from './Upgrading';
import Security from './Security';
import Top from './Top';
export default {
name: 'CruService',
components: {
Loading,
Tabbed,
Tab,
Top,
Command,
HealthCheck,
Networking,
Labels,
Security,
Upgrading,
Volumes,
Footer
},
mixins: [CreateEditView],
props: {
realMode: {
type: String,
required: true,
},
},
async fetch() {
const hash = await allHash({
configMaps: this.$store.dispatch('cluster/findAll', { type: CONFIG_MAP }),
secrets: this.$store.dispatch('cluster/findAll', { type: SECRET }),
services: this.$store.dispatch('cluster/findAll', { type: RIO.SERVICE }),
});
this.allSecrets = hash.secrets;
this.allConfigMaps = hash.configMaps;
},
data() {
if ( !this.value.spec ) {
this.value.spec = {};
}
const containerName = this.$route.query[EDIT_CONTAINER];
const rootSpec = this.value.spec;
const multipleContainers = ( !!(rootSpec.containers && rootSpec.containers.length) );
let spec = rootSpec;
let isSidecar = false;
let nameResource = this.value.metadata;
if ( !nameResource ) {
nameResource = { name: '' };
this.value.metadata = nameResource;
}
if ( containerName ) {
nameResource = spec.containers[name];
spec = nameResource.spec;
isSidecar = true;
}
if ( typeof spec.imagePullPolicy === 'undefined' ) {
spec.imagePullPolicy = 'Always';
}
const demoName = this.$route.query[DEMO];
let isDemo = false;
if ( demoName && DEMOS[demoName] ) {
isDemo = true;
Object.assign(spec, DEMOS[demoName].spec);
}
return {
multipleContainers,
nameResource,
containerName,
isSidecar,
rootSpec,
spec,
isDemo,
allConfigMaps: null,
allSecrets: null,
showTabs: false
};
},
computed: {
promptForContainer() {
return this.mode === _EDIT && this.multipleContainers && this.containerName === undefined;
},
namespace() {
return this.value.metadata.namespace;
},
configMaps() {
return matchingNamespaceGroupedByKey(this.allConfigMaps, this.namespace);
},
secrets() {
return matchingNamespaceGroupedByKey(this.allSecrets, this.namespace);
},
},
methods: {
selectContainer(name) {
this.$router.applyQuery({ [EDIT_CONTAINER]: name });
this.containerName = name;
},
remove(name) {
const containers = this.value.spec.containers;
const entry = findBy(containers, 'name', name);
removeObject(containers, entry);
this.save();
},
toggleTabs() {
this.showTabs = !this.showTabs;
},
get
},
};
function matchingNamespaceGroupedByKey(ary, namespace) {
if ( !namespace ) {
return [];
}
const matching = filterBy((ary || []), 'metadata.namespace', namespace);
const out = [];
for ( const item of matching ) {
const name = item.metadata.name;
const keys = [];
for ( const k of Object.keys(item.data || {}) ) {
keys.push({ label: k, value: `${ name }/${ k }` });
}
for ( const k of Object.keys(item.binaryData || {}) ) {
keys.push({ label: k, value: `${ name }/${ k }` });
}
if ( keys.length ) {
out.push({
group: item.metadata.name,
items: keys
});
}
}
return out;
}
</script>
<template>
<form>
<Loading v-if="$fetchState.pending" />
<div v-else-if="promptForContainer" class="clearfix">
<p>This service consists of multiple containers, which one do you want to edit?</p>
<div class="box">
<p>The primary container</p>
<p>{{ value.nameDisplay }}</p>
<button type="button" class="btn role-primary" @click="selectContainer('')">
Edit
</button>
</div>
<div v-for="choice in value.spec.containers" :key="choice.name" class="box">
<p>Sidecar</p>
<p>{{ choice.name }}</p>
<button type="button" class="btn role-primary" @click="selectContainer(choice.name)">
Edit
</button>
<button type="button" class="btn bg-error" @click="remove(choice.name)">
Delete
</button>
</div>
</div>
<div v-else>
<Top
:value="value"
:spec="spec"
:name-resource="nameResource"
:is-sidecar="isSidecar"
:mode="mode"
:real-mode="realMode"
:is-demo="isDemo"
:register-after-hook="registerAfterHook"
:register-before-hook="registerBeforeHook"
/>
<div class="spacer"></div>
<a href="#" @click.prevent="toggleTabs">
<span v-if="!showTabs">Show</span> <span v-else>Hide</span> additional options
</a>
<Tabbed v-show="showTabs" default-tab="command">
<Tab name="command" label="Command">
<Command
:spec="spec"
:mode="mode"
:config-maps="configMaps"
:secrets="secrets"
:namespace="namespace"
:more-add="true"
/>
</Tab>
<Tab name="network" label="Network">
<Networking :spec="spec" :mode="mode" />
</Tab>
<Tab name="healthcheck" label="Health Check">
<HealthCheck :spec="spec" :mode="mode" />
</Tab>
<Tab v-if="!isSidecar" name="labels" label="Labels">
<Labels :value="value" :mode="mode" />
</Tab>
<Tab name="security" label="Security">
<Security :spec="spec" :mode="mode" />
</Tab>
<Tab name="upgrading" label="Scaling & Upgrading">
<Upgrading :spec="rootSpec" :concurrency="get(rootSpec, 'autoscale.concurrency')" :mode="mode" />
</Tab>
<Tab v-if="false" name="volumes" label="Volumes">
<Volumes :spec="spec" :mode="mode" />
</Tab>
</Tabbed>
<Footer :mode="mode" :errors="errors" @save="save" @done="done" />
</div>
</form>
</template>
<style lang="scss" scoped>
.box {
float: left;
border: 1px solid var(--border);
padding: 20px;
text-align: center;
width: 25%;
margin-right: 20px;
P {
margin: 0;
}
&:last-child {
margin-right: 0;
}
}
</style>