✨ Deployments + rescale introduced
This commit is contained in:
parent
551d6b6faa
commit
a8050fa958
@ -133,7 +133,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tile, *[class^='tile-'], *[class*=' tile-'] {
|
.tile, *[class^='tile-'], *[class*=' tile-'] {
|
||||||
background-color: var(--background-color);
|
background-color: #ebebeb;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
12
classes/Deployment.ts
Normal file
12
classes/Deployment.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import type { Metadata } from "./Metadata";
|
||||||
|
|
||||||
|
export class Deployment
|
||||||
|
{
|
||||||
|
metadata?: Metadata;
|
||||||
|
spec?: DeploymentSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DeploymentSpec
|
||||||
|
{
|
||||||
|
replicas?: number;
|
||||||
|
}
|
||||||
62
components/RescaleDeploymentPopup.vue
Normal file
62
components/RescaleDeploymentPopup.vue
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<SmallPopupTemplate :heading="'Rescale ' + deployment.metadata?.name" ref="base">
|
||||||
|
<div class="content-l">
|
||||||
|
<div class="tile-m">
|
||||||
|
<p class="grayed-out">Deployment</p>
|
||||||
|
<p>{{ deployment.metadata?.namespace }}/{{ deployment.metadata?.name }}</p>
|
||||||
|
</div>
|
||||||
|
<UiInput>
|
||||||
|
<div class="rescale-input" v-if="deployment.spec?.replicas">
|
||||||
|
<UiButton class="square" icon="remove" @click="deployment.spec.replicas--"></UiButton>
|
||||||
|
<input type="number" v-model="deployment.spec.replicas" min="1">
|
||||||
|
<UiButton class="square" icon="add" @click="deployment.spec.replicas++"></UiButton>
|
||||||
|
</div>
|
||||||
|
</UiInput>
|
||||||
|
<div class="center">
|
||||||
|
<UiButton @click="() => rescale(deployment)">Rescale</UiButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SmallPopupTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Deployment } from '~/classes/Deployment';
|
||||||
|
import { rescaleDeployment } from '~/requests/deployments';
|
||||||
|
|
||||||
|
const base = ref();
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
deployment: Deployment
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function open()
|
||||||
|
{
|
||||||
|
base.value.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
})
|
||||||
|
|
||||||
|
function rescale(deployment: Deployment)
|
||||||
|
{
|
||||||
|
if(deployment.spec && deployment.spec.replicas)
|
||||||
|
{
|
||||||
|
rescaleDeployment(deployment, deployment.spec.replicas, () => {
|
||||||
|
base.value.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Error("Replica count is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rescale-input {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -6,6 +6,7 @@
|
|||||||
<NuxtLink class="resources" to="/dashboard/nodes">Nodes</NuxtLink>
|
<NuxtLink class="resources" to="/dashboard/nodes">Nodes</NuxtLink>
|
||||||
<NuxtLink class="resources" to="/dashboard/ingresses">Ingresses</NuxtLink>
|
<NuxtLink class="resources" to="/dashboard/ingresses">Ingresses</NuxtLink>
|
||||||
<NuxtLink class="resources" to="/dashboard/services">Services</NuxtLink>
|
<NuxtLink class="resources" to="/dashboard/services">Services</NuxtLink>
|
||||||
|
<NuxtLink class="resources" to="/dashboard/deployments">Deployments</NuxtLink>
|
||||||
<NuxtLink class="resources" to="/dashboard/pods">Pods</NuxtLink>
|
<NuxtLink class="resources" to="/dashboard/pods">Pods</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider" :class="{ hide: !inNamespaceScopedResource }"></div>
|
<div class="divider" :class="{ hide: !inNamespaceScopedResource }"></div>
|
||||||
|
|||||||
61
components/SmallPopupTemplate.vue
Normal file
61
components/SmallPopupTemplate.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="overlay center" @click="close" v-show="visible">
|
||||||
|
<div class="popup tile" @click.stop>
|
||||||
|
<div class="popup__header">
|
||||||
|
<h2>{{ heading }}</h2>
|
||||||
|
<UiButton class="square" icon="close" @click="close"></UiButton>
|
||||||
|
</div>
|
||||||
|
<div class="popup__body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import UiButton from './ui/UiButton.vue';
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
visible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
heading: String
|
||||||
|
})
|
||||||
|
defineExpose({
|
||||||
|
close,
|
||||||
|
open
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overlay {
|
||||||
|
background-color: rgba(0, 0, 0, 0.514);
|
||||||
|
backdrop-filter: blur(0.1rem);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup {
|
||||||
|
width: min(100%, 640px);
|
||||||
|
background-color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
25
components/deployments/DeploymentComponent.vue
Normal file
25
components/deployments/DeploymentComponent.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p class="grid-element" v-if="deployment.metadata">{{ deployment.metadata.name }}</p>
|
||||||
|
<p class="grid-element" v-if="deployment.metadata">{{ deployment.metadata.namespace }}</p>
|
||||||
|
<p class="grid-element" v-if="deployment.spec">{{ deployment.spec.replicas }}</p>
|
||||||
|
<div class="grid-element action-buttons">
|
||||||
|
<ActionButton>delete</ActionButton>
|
||||||
|
<ActionButton>autorenew</ActionButton>
|
||||||
|
<ActionButton @click="() => rescaleDeploymentPopup.open()">height</ActionButton>
|
||||||
|
</div>
|
||||||
|
<RescaleDeploymentPopup ref="rescaleDeploymentPopup" :deployment="deployment"></RescaleDeploymentPopup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Deployment } from '~/classes/Deployment';
|
||||||
|
import { rescaleDeployment } from '~/requests/deployments';
|
||||||
|
import RescaleDeploymentPopup from '../RescaleDeploymentPopup.vue';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
deployment: Deployment
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const rescaleDeploymentPopup = ref();
|
||||||
|
</script>
|
||||||
@ -1,3 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="resource-container deployment-container">
|
||||||
|
<div class="header">
|
||||||
|
<p>Name</p>
|
||||||
|
<p>Namespace</p>
|
||||||
|
<p>Replicas</p>
|
||||||
|
<p>Aktionen</p>
|
||||||
|
</div>
|
||||||
|
<DeploymentComponent :deployment="deployment" v-for="deployment, index in deployments" class="resource" :class="{ even: index % 2 }"></DeploymentComponent>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Deployment } from '~/classes/Deployment';
|
||||||
|
import { useNamespaceStore } from '#imports';
|
||||||
|
import type { Namespace } from '~/classes/Namespace';
|
||||||
|
import { getDeployments } from '~/requests/deployments';
|
||||||
|
import DeploymentComponent from '~/components/deployments/DeploymentComponent.vue';
|
||||||
|
|
||||||
|
const deployments: Ref<Deployment[] | undefined> = ref(undefined);
|
||||||
|
|
||||||
|
const namespace = computed(useNamespaceStore().getCurrentNamespace);
|
||||||
|
|
||||||
|
let interval: NodeJS.Timeout | undefined = undefined;
|
||||||
|
onMounted(() => {
|
||||||
|
watch(namespace, (newNamespace) => {
|
||||||
|
loadDeployments(newNamespace);
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = setInterval(() => {
|
||||||
|
loadDeployments(newNamespace);
|
||||||
|
}, 10000);
|
||||||
|
}, { immediate: true })
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadDeployments(namespace?: Namespace)
|
||||||
|
{
|
||||||
|
getDeployments(namespace?.metadata?.name, (_deployments: Deployment[]) => {
|
||||||
|
deployments.value = _deployments;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.deployment-container {
|
||||||
|
grid-template-columns: 1fr 1fr 1fr auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
requests/deployments.ts
Normal file
49
requests/deployments.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import type { Deployment } from "~/classes/Deployment";
|
||||||
|
|
||||||
|
export function getDeployments(namespace: string | undefined, onSuccess: (deployments: Deployment[]) => void)
|
||||||
|
{
|
||||||
|
axios.get<Deployment[]>(useRuntimeConfig().public.apiBase + '/deployments', {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + requireToken()
|
||||||
|
},
|
||||||
|
params: getParams(namespace)
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
onSuccess(response.data);
|
||||||
|
})
|
||||||
|
.catch();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rescaleDeployment(deployment: Deployment | undefined, replicaCount: number, onSuccess: () => void)
|
||||||
|
{
|
||||||
|
if(deployment == null || deployment.metadata == null)
|
||||||
|
{
|
||||||
|
throw new Error("Deployment or metadata cannot be null");
|
||||||
|
}
|
||||||
|
if(deployment.metadata.name == null || deployment.metadata.namespace == null)
|
||||||
|
{
|
||||||
|
throw new Error("Name or namespace cannot be null");
|
||||||
|
}
|
||||||
|
axios.patch<Deployment[]>(useRuntimeConfig().public.apiBase + '/deployments/' + deployment.metadata.namespace + "/" + deployment.metadata.name, replicaCount, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer " + requireToken(),
|
||||||
|
"Content-Type": "text/plain"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
onSuccess();
|
||||||
|
})
|
||||||
|
.catch();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParams(namespace: string | undefined)
|
||||||
|
{
|
||||||
|
if(namespace != undefined)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
namespace: namespace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user