🩹 Fixing minor bugs
This commit is contained in:
parent
ee5ed78d35
commit
08fbf78a76
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
html {
|
html {
|
||||||
--primary-color: rgb(87, 75, 255);
|
--primary-color: rgb(87, 75, 255);
|
||||||
|
--primary-color-dark: rgb(69, 57, 241);
|
||||||
--tile-color: #ebf1ff;
|
--tile-color: #ebf1ff;
|
||||||
background-color: rgb(255, 255, 255);
|
background-color: rgb(255, 255, 255);
|
||||||
--shade-light: #f3f3f3;
|
--shade-light: #f3f3f3;
|
||||||
|
|||||||
BIN
assets/transparent_logo.png
Normal file
BIN
assets/transparent_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
@ -4,6 +4,7 @@ export class NodeStats
|
|||||||
{
|
{
|
||||||
constructor (
|
constructor (
|
||||||
public node: Node,
|
public node: Node,
|
||||||
|
public runningPods: number
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
relativeCpuUsage?: number;
|
relativeCpuUsage?: number;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<PopupTemplate :heading="'Logs: ' + pod.metadata?.namespace + '/' + pod.metadata?.name" ref="base">
|
<PopupTemplate :heading="'Logs: ' + pod.metadata?.namespace + '/' + pod.metadata?.name" ref="base" @close="emits('close')">
|
||||||
<ScrollComponent ref="scrollComponent" v-show="logs">
|
<ScrollComponent ref="scrollComponent" v-show="logs">
|
||||||
<div class="console" v-if="logs">
|
<div class="console" v-if="logs">
|
||||||
<p class="log" v-for="log, index in logs" :class="{ even: index % 2 }"><span>[{{ dayjs(log.timestamp).format('YYYY-MM-DD HH:mm') }}]</span><span>{{ log.message }}</span></p>
|
<p class="log" v-for="log, index in logs" :class="{ even: index % 2 }"><span>[{{ dayjs(log.timestamp).format('YYYY-MM-DD HH:mm') }}]</span><span>{{ log.message }}</span></p>
|
||||||
@ -25,20 +25,25 @@ const props = defineProps<{
|
|||||||
pod: Pod
|
pod: Pod
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
const scrollComponent = ref();
|
const scrollComponent = ref();
|
||||||
|
|
||||||
function open()
|
onMounted(() => {
|
||||||
{
|
getLogs(props.pod.metadata.uid, (_logs: Log[]) => {
|
||||||
logs.value = undefined;
|
|
||||||
base.value.open();
|
|
||||||
getLogs(props.pod.metadata?.uid, (_logs: Log[]) => {
|
|
||||||
logs.value = _logs;
|
logs.value = _logs;
|
||||||
scrollComponent.value.scrollToBottom();
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
defineExpose({
|
onMounted(() => {
|
||||||
open
|
document.addEventListener('keydown', (event) => {
|
||||||
|
if(event.key === 'Escape')
|
||||||
|
{
|
||||||
|
emits('close');
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
<div class="grid-element">
|
<div class="grid-element">
|
||||||
<p>{{ calcAge(nodeStats.node?.metadata?.creationTimestamp) }}</p>
|
<p>{{ calcAge(nodeStats.node?.metadata?.creationTimestamp) }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="grid-element">{{ nodeStats.runningPods }}</p>
|
||||||
<div class="grid-element">
|
<div class="grid-element">
|
||||||
<NodeReadyComponent :ready="isReady(nodeStats)"></NodeReadyComponent>
|
<NodeReadyComponent :ready="isReady(nodeStats)"></NodeReadyComponent>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
<nav class="sidebar">
|
<nav class="sidebar">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</nav>
|
</nav>
|
||||||
<AccountPopup ref="accountPopup"></AccountPopup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div @click="() => viewIngressPopup.open()">
|
<div @click="() => showViewPopup = true">
|
||||||
<p class="grid-element">{{ ingress.metadata.name }}</p>
|
<p class="grid-element">{{ ingress.metadata.name }}</p>
|
||||||
<p class="grid-element">{{ ingress.metadata.namespace }}</p>
|
<p class="grid-element">{{ ingress.metadata.namespace }}</p>
|
||||||
<p class="grid-element">{{ ingress.spec.ingressClassName }}</p>
|
<p class="grid-element">{{ ingress.spec.ingressClassName }}</p>
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="grid-element action-buttons">
|
<div class="grid-element action-buttons">
|
||||||
<ActionButton>delete</ActionButton>
|
<ActionButton>delete</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
<IngressViewPopup :ingress="ingress" ref="viewIngressPopup"></IngressViewPopup>
|
<IngressViewPopup v-if="showViewPopup" :ingress="ingress" ref="viewIngressPopup" @close="showViewPopup = false"></IngressViewPopup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -19,5 +19,5 @@ defineProps<{
|
|||||||
ingress: Ingress
|
ingress: Ingress
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const viewIngressPopup = ref();
|
const showViewPopup = ref(false);
|
||||||
</script>
|
</script>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<PopupTemplate ref="base" :heading="ingress.metadata?.name + '/' + ingress.metadata?.namespace">
|
<PopupTemplate ref="base" @close="emits('close')" :heading="StringUtils.format('%s/%s', ingress.metadata.namespace, ingress.metadata.name)">
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<div class="content-l">
|
<div class="content-l">
|
||||||
<h2>General</h2>
|
<h2>General</h2>
|
||||||
@ -36,6 +36,10 @@ defineProps<{
|
|||||||
ingress: Ingress
|
ingress: Ingress
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
function open()
|
function open()
|
||||||
{
|
{
|
||||||
base.value.open();
|
base.value.open();
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<p>Name</p>
|
<p>Name</p>
|
||||||
<p>Alter</p>
|
<p>Alter</p>
|
||||||
|
<p>Pods</p>
|
||||||
<p>Status</p>
|
<p>Status</p>
|
||||||
<p>CPU</p>
|
<p>CPU</p>
|
||||||
<p>RAM</p>
|
<p>RAM</p>
|
||||||
@ -23,6 +24,6 @@ const node = ResourceRepo.init<NodeStats>().load('nodes').get();
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.node-container {
|
.node-container {
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -3,14 +3,14 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="left-center">
|
<div class="left-center">
|
||||||
<p>Name</p>
|
<p>Name</p>
|
||||||
<UiButton icon="add" class="extra-small" reverse @click="() => secretAddComponent.open()">Add</UiButton>
|
<UiButton v-if="false" icon="add" class="extra-small" reverse @click="() => secretAddComponent.open()">Add</UiButton>
|
||||||
</div>
|
</div>
|
||||||
<p>Namespace</p>
|
<p>Namespace</p>
|
||||||
<p>Alter</p>
|
<p>Alter</p>
|
||||||
<p>Aktionen</p>
|
<p>Aktionen</p>
|
||||||
</div>
|
</div>
|
||||||
<SecretComponent v-for="secret, index in secrets" :secret="secret" class="resource" :class="{ even: index % 2 }"></SecretComponent>
|
<SecretComponent v-for="secret, index in secrets" :secret="secret" class="resource" :class="{ even: index % 2 }"></SecretComponent>
|
||||||
<SecretAddComponent ref="secretAddComponent"></SecretAddComponent>
|
<SecretAddComponent v-if="false" ref="secretAddComponent"></SecretAddComponent>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div @click="() => podViewPopup.open()">
|
<div>
|
||||||
<p class="grid-element" v-if="pod.metadata">{{ pod.metadata.name }}</p>
|
<p class="grid-element pointer" v-if="pod.metadata" @click="() => showViewPopup = true">{{ pod.metadata.name }}</p>
|
||||||
<p class="grid-element" v-if="pod.metadata">{{ pod.metadata.namespace }}</p>
|
<p class="grid-element" v-if="pod.metadata">{{ pod.metadata.namespace }}</p>
|
||||||
<p class="grid-element" v-if="pod.metadata">{{ calcAge(pod.metadata.creationTimestamp) }}</p>
|
<p class="grid-element" v-if="pod.metadata">{{ calcAge(pod.metadata.creationTimestamp) }}</p>
|
||||||
<p class="grid-element" v-if="pod.spec">{{ pod.spec.nodeName }}</p>
|
<p class="grid-element" v-if="pod.spec">{{ pod.spec.nodeName }}</p>
|
||||||
@ -8,12 +8,13 @@
|
|||||||
<PhaseComponent v-if="pod.status" :phase="pod.status.phase"></PhaseComponent>
|
<PhaseComponent v-if="pod.status" :phase="pod.status.phase"></PhaseComponent>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-element action-buttons">
|
<div class="grid-element action-buttons">
|
||||||
<ActionButton @click="() => logPopup.open()">text_snippet</ActionButton>
|
<ActionButton @click="showLogPopup = true">text_snippet</ActionButton>
|
||||||
<ActionButton>open_in_full</ActionButton>
|
<ActionButton>open_in_full</ActionButton>
|
||||||
<ActionButton @click="() => deletePod(pod.metadata?.uid, () => {})" v-if="hasAnyRole(getUser(), ['admin', 'maintainer'])">delete</ActionButton>
|
<ActionButton @click="showDeletePopup = true" v-if="hasAnyRole(getUser(), ['admin', 'maintainer'])">delete</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
<LogPopup :pod="pod" ref="logPopup"></LogPopup>
|
<PodDeletePopup v-if="showDeletePopup" :pod="pod" @close="showDeletePopup = false"></PodDeletePopup>
|
||||||
<PodViewPopup :pod="pod" ref="podViewPopup"></PodViewPopup>
|
<LogPopup v-if="showLogPopup" :pod="pod" @close="showLogPopup = false"></LogPopup>
|
||||||
|
<PodViewPopup v-if="showViewPopup" :pod="pod" @close="showViewPopup = false"></PodViewPopup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -21,13 +22,13 @@
|
|||||||
import type { Pod } from '~/classes/Pod';
|
import type { Pod } from '~/classes/Pod';
|
||||||
import { calcAge } from '~/classes/Pod';
|
import { calcAge } from '~/classes/Pod';
|
||||||
import { hasAnyRole } from '~/classes/User';
|
import { hasAnyRole } from '~/classes/User';
|
||||||
import { deletePod } from '~/requests/pod';
|
import PodDeletePopup from './view/PodDeletePopup.vue';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
pod: Pod
|
pod: Pod
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const logPopup = ref();
|
const showDeletePopup = ref(false);
|
||||||
|
const showLogPopup = ref(false);
|
||||||
const podViewPopup = ref();
|
const showViewPopup = ref(false);
|
||||||
</script>
|
</script>
|
||||||
36
components/pod/view/PodDeletePopup.vue
Normal file
36
components/pod/view/PodDeletePopup.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<PopupTemplate size="SMALL" heading="Delete Pod" @close="emits('close')">
|
||||||
|
<div class="content-l">
|
||||||
|
<div class="content-m">
|
||||||
|
<div class="tile-m">
|
||||||
|
<h3>Namespace</h3>
|
||||||
|
<p>{{ pod.metadata.namespace }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="tile-m">
|
||||||
|
<h3>Name</h3>
|
||||||
|
<p>{{ pod.metadata.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="center">
|
||||||
|
<UiButton class="width-6rem hollow">Cancel</UiButton>
|
||||||
|
<UiButton class="width-6rem" icon="delete" reverse>Delete</UiButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PopupTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { type Pod } from '~/classes/Pod';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
pod: Pod
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<PopupTemplate ref="base" :heading="StringUtils.format('%s/%s', pod.metadata.namespace, pod.metadata.name)">
|
<PopupTemplate ref="base" :heading="StringUtils.format('%s/%s', pod.metadata.namespace, pod.metadata.name)" @close="emits('close')">
|
||||||
<div class="col-2 expand">
|
<div class="col-2 expand">
|
||||||
<div class="content-l">
|
<div class="content-l">
|
||||||
<h2>General</h2>
|
<h2>General</h2>
|
||||||
@ -25,7 +25,9 @@
|
|||||||
</UiInput>
|
</UiInput>
|
||||||
<ScrollComponent>
|
<ScrollComponent>
|
||||||
<div>
|
<div>
|
||||||
<p class="env" v-for="env, index in filteredEnv">{{ env.key }} = {{ env.value }}</p>
|
<div class="env" v-for="env in filteredEnv">
|
||||||
|
<UiMask class="spaced-center" :prefix="env.key" :enabled="isSensitive(env.key)" :value="env.value"></UiMask>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ScrollComponent>
|
</ScrollComponent>
|
||||||
</div>
|
</div>
|
||||||
@ -38,6 +40,7 @@ import { calcAge, type Pod } from '~/classes/Pod';
|
|||||||
import PhaseComponent from '~/components/PhaseComponent.vue';
|
import PhaseComponent from '~/components/PhaseComponent.vue';
|
||||||
import { EnvVar } from '../env/EnvVar';
|
import { EnvVar } from '../env/EnvVar';
|
||||||
import ScrollComponent from '~/components/ScrollComponent.vue';
|
import ScrollComponent from '~/components/ScrollComponent.vue';
|
||||||
|
import UiMask from '~/components/ui/UiMask.vue';
|
||||||
|
|
||||||
const base = ref();
|
const base = ref();
|
||||||
|
|
||||||
@ -45,6 +48,10 @@ const props = defineProps<{
|
|||||||
pod: Pod
|
pod: Pod
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
const envs: Ref<EnvVar[] | undefined> = ref(undefined);
|
const envs: Ref<EnvVar[] | undefined> = ref(undefined);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
EnvVar.get(props.pod.metadata.namespace, props.pod.metadata.name, (_envs: EnvVar[]) => {
|
EnvVar.get(props.pod.metadata.namespace, props.pod.metadata.name, (_envs: EnvVar[]) => {
|
||||||
@ -74,6 +81,19 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|
||||||
|
function isSensitive(key: string)
|
||||||
|
{
|
||||||
|
const markers = ["token", "key", "password", "secret", "private", "credential", "auth", "jwt"];
|
||||||
|
for (const marker of markers)
|
||||||
|
{
|
||||||
|
if (key.toLowerCase().includes(marker) && !key.toLowerCase().includes("public"))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -87,4 +107,8 @@ defineExpose({ open });
|
|||||||
.env:hover {
|
.env:hover {
|
||||||
background-color: #cecece;
|
background-color: #cecece;
|
||||||
}
|
}
|
||||||
|
.env {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="overlay center" @click="close" v-show="visible">
|
<div class="overlay center" @click="close" v-show="visible || true">
|
||||||
<div class="popup" :class="size" @click.stop>
|
<div class="popup" :class="size" @click.stop>
|
||||||
<div class="popup__header">
|
<div class="popup__header">
|
||||||
<h2>{{ heading }}</h2>
|
<h2>{{ heading }}</h2>
|
||||||
@ -15,8 +15,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
enableScrolling();
|
enableScrolling();
|
||||||
|
emits('close');
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,4 +97,8 @@ function enableScrolling()
|
|||||||
height: auto;
|
height: auto;
|
||||||
width: 740px;
|
width: 740px;
|
||||||
}
|
}
|
||||||
|
.SMALL {
|
||||||
|
height: auto;
|
||||||
|
width: 540px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -44,6 +44,7 @@ const props = defineProps<{
|
|||||||
}
|
}
|
||||||
.button:hover {
|
.button:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-color: var(--primary-color-dark);
|
||||||
}
|
}
|
||||||
.button * {
|
.button * {
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
31
components/ui/UiMask.vue
Normal file
31
components/ui/UiMask.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ui-mask">
|
||||||
|
<p><span>{{ prefix }}</span>: <span>{{ display }}</span></p>
|
||||||
|
<UiIcon @click="show = !show" class="pointer" v-if="enabled">visibility</UiIcon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
prefix: string,
|
||||||
|
enabled: boolean,
|
||||||
|
value: string
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
|
||||||
|
const display = computed(() => {
|
||||||
|
if (props.enabled && show.value === false)
|
||||||
|
{
|
||||||
|
const length = props.value.length;
|
||||||
|
return "*".repeat(length);
|
||||||
|
}
|
||||||
|
return props.value;
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ui-mask {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -5,10 +5,19 @@
|
|||||||
<NuxtLink to="/account/inspect/nodes/_all">Inspect</NuxtLink>
|
<NuxtLink to="/account/inspect/nodes/_all">Inspect</NuxtLink>
|
||||||
<NuxtLink to="/account/monitorings/nodes">Monitorings</NuxtLink>
|
<NuxtLink to="/account/monitorings/nodes">Monitorings</NuxtLink>
|
||||||
<NuxtLink to="/account/settings">Settings</NuxtLink>
|
<NuxtLink to="/account/settings">Settings</NuxtLink>
|
||||||
|
<p class="pointer" @click="logout()">Logout</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
function logout()
|
||||||
|
{
|
||||||
|
useCookie('session').value = null;
|
||||||
|
useRouter().push('/');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.account-page {
|
.account-page {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="login-wrapper">
|
<div class="login-wrapper">
|
||||||
<div class="tile-l login-window">
|
<div class="tile-l login-window">
|
||||||
<h2>Kubooboo</h2>
|
<h2>Kubooboo</h2>
|
||||||
<img class="logo" src="@/assets/logo.png" alt="">
|
<img class="logo" src="@/assets/transparent_logo.png" alt="">
|
||||||
<form class="login content-xl" @submit.prevent="doLogin()">
|
<form class="login content-xl" @submit.prevent="doLogin()">
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
@ -20,7 +20,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user