✨ Deployments + rescale introduced
This commit is contained in:
parent
551d6b6faa
commit
a8050fa958
@ -133,7 +133,7 @@
|
||||
}
|
||||
|
||||
.tile, *[class^='tile-'], *[class*=' tile-'] {
|
||||
background-color: var(--background-color);
|
||||
background-color: #ebebeb;
|
||||
border-radius: 0.25rem;
|
||||
overflow: hidden;
|
||||
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/ingresses">Ingresses</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>
|
||||
</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>
|
||||
|
||||
<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