✨ Add Popup for node inspection
This commit is contained in:
parent
9afc5d8eab
commit
5104631bd2
2
app.vue
2
app.vue
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<NuxtPage></NuxtPage>
|
||||
<component :is="usePopup().get()"></component>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RouteLocation } from 'vue-router';
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
// Guard dashboard and redirect to login
|
||||
useRouter().beforeEach((route: RouteLocation) => {
|
||||
|
||||
@ -1,29 +1,100 @@
|
||||
import { Metadata } from "../Metadata";
|
||||
import { type HasMetadata } from "../repo/ResourceRepo";
|
||||
import {State} from "~/classes/Threshold";
|
||||
|
||||
export class Node implements HasMetadata
|
||||
{
|
||||
constructor (
|
||||
public metadata: Metadata,
|
||||
public metrics: NodeMetrics,
|
||||
public status: Status
|
||||
public status: Status,
|
||||
public spec: Spec
|
||||
) { }
|
||||
|
||||
static cpuUsageFlag(usage: number): State
|
||||
{
|
||||
if(usage < 20)
|
||||
{
|
||||
return State.GREEN;
|
||||
}
|
||||
if(usage < 60)
|
||||
{
|
||||
return State.ORANGE;
|
||||
}
|
||||
return State.RED;
|
||||
}
|
||||
|
||||
static memoryUsageFlag(usage: number)
|
||||
{
|
||||
if(usage < 30)
|
||||
{
|
||||
return State.GREEN;
|
||||
}
|
||||
if(usage < 75)
|
||||
{
|
||||
return State.ORANGE;
|
||||
}
|
||||
return State.RED;
|
||||
}
|
||||
|
||||
static diskUsageFlag(usage: number)
|
||||
{
|
||||
if(usage < 30)
|
||||
{
|
||||
return State.GREEN;
|
||||
}
|
||||
if(usage < 70)
|
||||
{
|
||||
return State.ORANGE;
|
||||
}
|
||||
return State.RED;
|
||||
}
|
||||
|
||||
static isReady(node: Node): boolean | undefined
|
||||
{
|
||||
const conditions = node.status.conditions;
|
||||
if(conditions != undefined)
|
||||
{
|
||||
for(const condition of conditions)
|
||||
{
|
||||
if(condition.type === "Ready" && condition.status === "True")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class NodeMetrics
|
||||
{
|
||||
absoluteCpuUsage?: number;
|
||||
relativeCpuUsage?: number;
|
||||
totalCpu?: number;
|
||||
absoluteMemory?: number;
|
||||
relativeMemory?: number;
|
||||
totalMemory?: number;
|
||||
runningPods?: number;
|
||||
relativeDiskUsage?: number;
|
||||
totalDiskSpace?: number;
|
||||
|
||||
}
|
||||
|
||||
class Spec
|
||||
{
|
||||
constructor (
|
||||
public taints?: Taint[]
|
||||
) {}
|
||||
}
|
||||
|
||||
class Status
|
||||
{
|
||||
constructor (
|
||||
public nodeInfo: NodeInfo
|
||||
) {}
|
||||
|
||||
conditions?: Condition[]
|
||||
}
|
||||
|
||||
@ -31,4 +102,20 @@ class Condition
|
||||
{
|
||||
type?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
class Taint
|
||||
{
|
||||
constructor (
|
||||
public key: string,
|
||||
public effect: string
|
||||
) {}
|
||||
}
|
||||
|
||||
class NodeInfo
|
||||
{
|
||||
constructor (
|
||||
public osImage: string,
|
||||
public kubeletVersion: string
|
||||
) {}
|
||||
}
|
||||
@ -31,7 +31,7 @@ defineProps<{
|
||||
background-color: rgb(139, 255, 139);
|
||||
}
|
||||
.outer.green .inner {
|
||||
background-color: green;
|
||||
background-color: #11cc11;
|
||||
}
|
||||
|
||||
.outer.orange {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { ConfigMap } from '~/classes/ConfigMap';
|
||||
import PopupTemplate from '~/components/popup/PopupTemplate.vue';
|
||||
import { Prompt, PromptType } from '~/components/ui/Prompt';
|
||||
import { Prompt, PromptType } from '~/components/ui/prompt/Prompt';
|
||||
|
||||
defineProps<{
|
||||
configMap: ConfigMap
|
||||
|
||||
@ -1,32 +1,26 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="grid-element" @click="() => showViewPopup = true">{{ deployment.metadata.name }}</p>
|
||||
<p class="grid-element" @click="usePopup().open(DeploymentViewPopup, deployment)">{{ deployment.metadata.name }}</p>
|
||||
<p class="grid-element">{{ deployment.metadata.namespace }}</p>
|
||||
<p class="grid-element">{{ calcAge(deployment.metadata.creationTimestamp) }}</p>
|
||||
<p class="grid-element">{{ deployment.spec.replicas }}</p>
|
||||
<div class="grid-element action-buttons">
|
||||
<ActionButton @click="() => showLogsPopup = true">text_snippet</ActionButton>
|
||||
<ActionButton @click="usePopup().open(DeploymentLogPopup, deployment)">text_snippet</ActionButton>
|
||||
<ActionButton>autorenew</ActionButton>
|
||||
<ActionButton @click="() => rescaleDeploymentPopup.open()">height</ActionButton>
|
||||
<ActionButton @click="usePopup().open(DeploymentRescalePopup, deployment)">height</ActionButton>
|
||||
</div>
|
||||
<RescaleDeploymentPopup ref="rescaleDeploymentPopup" :deployment="deployment"></RescaleDeploymentPopup>
|
||||
<DeploymentViewPopup v-if="showViewPopup" :deployment="deployment" @close="() => showViewPopup = false"></DeploymentViewPopup>
|
||||
<DeploymentLogPopup v-if="showLogsPopup" :deployment="deployment" @close="() => showLogsPopup = false"></DeploymentLogPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Deployment } from '~/classes/Deployment';
|
||||
import { calcAge } from '~/classes/Pod';
|
||||
import RescaleDeploymentPopup from '../RescaleDeploymentPopup.vue';
|
||||
import DeploymentRescalePopup from './view/DeploymentRescalePopup.vue';
|
||||
import DeploymentViewPopup from "~/components/deployment/view/DeploymentViewPopup.vue";
|
||||
import DeploymentLogPopup from "~/components/inspect/logs/DeploymentLogPopup.vue";
|
||||
import DeploymentLogPopup from "~/components/deployment/view/DeploymentLogPopup.vue";
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
defineProps<{
|
||||
deployment: Deployment
|
||||
}>();
|
||||
|
||||
const rescaleDeploymentPopup = ref();
|
||||
const showViewPopup = ref(false);
|
||||
const showLogsPopup = ref(false);
|
||||
</script>
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<PopupTemplate :heading="'Logs: ' + deployment.metadata.namespace + '/' + deployment.metadata.name" ref="base" @close="emits('close')">
|
||||
<div class="log-container" v-if="pods">
|
||||
<PopupTemplate :heading="StringUtils.format('Logs: %s/%s', deployment.metadata.namespace, deployment.metadata.name)">
|
||||
<div class="log-container">
|
||||
<div class="spaced-center">
|
||||
<div class="left-center">
|
||||
<UiButton @click="() => config.timestamps = true" v-if="!config.timestamps"><span>Show Timestamp</span> <UiIcon>visibility</UiIcon></UiButton>
|
||||
@ -20,47 +20,27 @@
|
||||
import { LogRepo } from '~/classes/LogRepo';
|
||||
import { Pod } from '~/classes/Pod';
|
||||
import { Log } from '~/requests/logs';
|
||||
import Console from "~/components/inspect/logs/Console.vue";
|
||||
import Console from "~/components/inspect/console/Console.vue";
|
||||
import type {Deployment} from "~/classes/Deployment";
|
||||
import UiIcon from "~/components/ui/UiIcon.vue";
|
||||
import { ConsoleConfig } from '~/components/inspect/logs/ConsoleConfig'
|
||||
import { ConsoleConfig } from '~/components/inspect/console/ConsoleConfig'
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
const config = ref(ConsoleConfig.default(true, true, false));
|
||||
|
||||
const base = ref();
|
||||
|
||||
const logs: Ref<Log[]> = ref([]);
|
||||
const pods: Ref<Pod[] | undefined> = ref(undefined);
|
||||
|
||||
const props = defineProps<{
|
||||
deployment: Deployment
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
}>()
|
||||
const deployment = usePopup().data() as Deployment;
|
||||
|
||||
const logRepo = new LogRepo();
|
||||
onMounted(() => {
|
||||
logRepo.listen("deployments", props.deployment.metadata.namespace, props.deployment.metadata.name,(_logs: Log[]) => {
|
||||
logRepo.listen("deployments", deployment.metadata.namespace, deployment.metadata.name,(_logs: Log[]) => {
|
||||
logs.value.push(..._logs);
|
||||
});
|
||||
Pod.getByDeployment(props.deployment.metadata.namespace, props.deployment.metadata.name, (_pods: Pod[]) => {
|
||||
pods.value = _pods;
|
||||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
logRepo.clear();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if(event.key === 'Escape')
|
||||
{
|
||||
emits('close');
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -22,28 +22,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { Deployment } from '~/classes/Deployment';
|
||||
import { rescaleDeployment } from '~/requests/deployments';
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
const base = ref();
|
||||
|
||||
defineProps<{
|
||||
deployment: Deployment
|
||||
}>();
|
||||
|
||||
function open()
|
||||
{
|
||||
base.value.open();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
const deployment = usePopup().data() as Deployment;
|
||||
|
||||
function rescale(deployment: Deployment)
|
||||
{
|
||||
if(deployment.spec && deployment.spec.replicas)
|
||||
{
|
||||
rescaleDeployment(deployment, deployment.spec.replicas, () => {
|
||||
base.value.close();
|
||||
usePopup().close();
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -71,10 +71,9 @@
|
||||
import PopupTemplate from "~/components/popup/PopupTemplate.vue";
|
||||
import type { Deployment } from "~/classes/Deployment";
|
||||
import {calcAge, Pod} from "~/classes/Pod";
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
const props = defineProps<{
|
||||
deployment: Deployment
|
||||
}>()
|
||||
const deployment = usePopup().data() as Deployment;
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
@ -92,7 +91,7 @@ onMounted(() => {
|
||||
const pods: Ref<Pod[] | undefined> = ref();
|
||||
|
||||
onMounted(() => {
|
||||
Pod.getByDeployment(props.deployment.metadata.namespace, props.deployment.metadata.name, (_pods: Pod[]) => {
|
||||
Pod.getByDeployment(deployment.metadata.namespace, deployment.metadata.name, (_pods: Pod[]) => {
|
||||
pods.value = _pods;
|
||||
});
|
||||
})
|
||||
|
||||
24
components/inspect/ResourceType.ts
Normal file
24
components/inspect/ResourceType.ts
Normal file
@ -0,0 +1,24 @@
|
||||
export enum ResourceType
|
||||
{
|
||||
// Cluster Resources
|
||||
NODE = "nodes",
|
||||
NAMESPACE = "namespaces",
|
||||
CUSTOM_RESOURCE_DEFINITION = "custom-resource-definitions",
|
||||
|
||||
// Workloads
|
||||
STATEFUL_SET = "stateful-sets",
|
||||
DEPLOYMENT = "deployments",
|
||||
POD = "pods",
|
||||
|
||||
// Networking
|
||||
SERVICE = "services",
|
||||
INGRESS = "ingresses",
|
||||
|
||||
// Config
|
||||
SECRET = "secrets",
|
||||
CONFIG_MAP = "config-maps",
|
||||
|
||||
// Storage
|
||||
PVC = "pvcs",
|
||||
PV = "pvs",
|
||||
}
|
||||
@ -12,7 +12,7 @@
|
||||
<script setup lang="ts">
|
||||
import type {Log} from "~/requests/logs";
|
||||
import dayjs from "dayjs";
|
||||
import type {ConsoleConfig} from "~/components/inspect/logs/ConsoleConfig";
|
||||
import type {ConsoleConfig} from "~/components/inspect/console/ConsoleConfig";
|
||||
|
||||
const props = defineProps<{
|
||||
config: ConsoleConfig
|
||||
@ -16,10 +16,11 @@
|
||||
import type { ConfigMap } from '~/classes/ConfigMap';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import ConfigMapComponent from '~/components/configmap/ConfigMapComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<ConfigMap>();
|
||||
onMounted(() => {
|
||||
repo.listen("config-maps");
|
||||
repo.listen(ResourceType.CONFIG_MAP);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -16,10 +16,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import type {CustomResourceDefinition} from "~/classes/CustomResourceDefinition";
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<CustomResourceDefinition>();
|
||||
onMounted(() => {
|
||||
repo.listen("custom-resource-definitions");
|
||||
repo.listen(ResourceType.CUSTOM_RESOURCE_DEFINITION);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -17,10 +17,11 @@
|
||||
import type { Deployment } from '~/classes/Deployment';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import DeploymentComponent from "~/components/deployment/DeploymentComponent.vue";
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Deployment>();
|
||||
onMounted(() => {
|
||||
repo.listen("deployments");
|
||||
repo.listen(ResourceType.DEPLOYMENT);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -16,10 +16,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { Ingress } from '~/classes/Ingress';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Ingress>();
|
||||
onMounted(() => {
|
||||
repo.listen("ingresses");
|
||||
repo.listen(ResourceType.INGRESS);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -14,10 +14,11 @@
|
||||
import type { Namespace } from '~/classes/Namespace';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import NamespaceComponent from '~/components/NamespaceComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Namespace>();
|
||||
onMounted(() => {
|
||||
repo.listen("namespaces");
|
||||
repo.listen(ResourceType.NAMESPACE);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<p>Memory</p>
|
||||
<p>Disk Usage</p>
|
||||
</div>
|
||||
<NodeComponent :node-stats="ns" v-for="(ns, index) in node" class="resource" :class="{ even: index % 2 }"></NodeComponent>
|
||||
<NodeComponent :node="ns" v-for="(ns, index) in node" class="resource" :class="{ even: index % 2 }"></NodeComponent>
|
||||
</div>
|
||||
</TableComponent>
|
||||
</template>
|
||||
@ -18,9 +18,10 @@
|
||||
<script setup lang="ts">
|
||||
import type { Node } from '~/classes/node/Node';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import NodeComponent from '~/components/NodeComponent.vue';
|
||||
import NodeComponent from '~/components/node/NodeComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const node = ResourceRepo.init<Node>().load('nodes').get();
|
||||
const node = ResourceRepo.init<Node>().load(ResourceType.NODE).get();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -17,11 +17,12 @@
|
||||
import type { PersistentVolumeClaim } from '~/classes/PersistentVolumeClaim';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import PersistentVolumeClaimComponent from '~/components/PersistentVolumeClaimComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<PersistentVolumeClaim>();
|
||||
|
||||
onMounted(() => {
|
||||
repo.listen("pvcs");
|
||||
repo.listen(ResourceType.PVC);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -14,11 +14,12 @@
|
||||
import type { PersistentVolume } from '~/classes/PersistentVolume';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import PersistentVolumeComponent from '~/components/PersistentVolumeComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<PersistentVolume>();
|
||||
|
||||
onMounted(() => {
|
||||
repo.listen("pvs");
|
||||
repo.listen(ResourceType.PV);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -20,10 +20,11 @@
|
||||
import type { Pod } from '~/classes/Pod';
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import PodComponent from '~/components/pod/PodComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Pod>();
|
||||
onMounted(() => {
|
||||
repo.listen("pods");
|
||||
repo.listen(ResourceType.POD);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -20,11 +20,12 @@
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import type { Secret } from '~/classes/Secret';
|
||||
import SecretComponent from '~/components/secrets/SecretComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Secret>();
|
||||
|
||||
onMounted(() => {
|
||||
repo.listen("secrets");
|
||||
repo.listen(ResourceType.SECRET);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -15,10 +15,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import type { Service } from '~/classes/Service';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<Service>();
|
||||
onMounted(() => {
|
||||
repo.listen("services");
|
||||
repo.listen(ResourceType.SERVICE);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -16,10 +16,11 @@
|
||||
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||
import type { StatefulSet } from '~/classes/StatefulSet';
|
||||
import StatefulSetComponent from '~/components/statefulset/StatefulSetComponent.vue';
|
||||
import {ResourceType} from "~/classes/ResourceTypes";
|
||||
|
||||
const repo = ResourceRepo.init<StatefulSet>();
|
||||
onMounted(() => {
|
||||
repo.listen("stateful-sets");
|
||||
repo.listen(ResourceType.STATEFUL_SET);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
repo.clear();
|
||||
|
||||
@ -1,37 +1,41 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="grid-element" v-if="nodeStats && nodeStats.metadata">{{ nodeStats.metadata.name }}</p>
|
||||
<p class="grid-element" v-if="node && node.metadata" @click="usePopup().open(NodeViewComponent, node)">{{
|
||||
node.metadata.name
|
||||
}}</p>
|
||||
<div class="grid-element">
|
||||
<p>{{ calcAge(nodeStats.metadata?.creationTimestamp) }}</p>
|
||||
<p>{{ calcAge(node.metadata.creationTimestamp) }}</p>
|
||||
</div>
|
||||
<p class="grid-element">{{ nodeStats.metrics.runningPods }}</p>
|
||||
<p class="grid-element">{{ node.metrics.runningPods }}</p>
|
||||
<div class="grid-element">
|
||||
<NodeReadyComponent :ready="isReady(nodeStats)"></NodeReadyComponent>
|
||||
<NodeReadyComponent :ready="isReady(node)"></NodeReadyComponent>
|
||||
</div>
|
||||
<div class="grid-element">
|
||||
<p class="usage" :class="cpuUsageFlag(nodeStats.metrics.relativeCpuUsage)">{{ nodeStats.metrics.relativeCpuUsage }}%</p>
|
||||
<p class="usage" :class="cpuUsageFlag(node.metrics.relativeCpuUsage)">{{ node.metrics.relativeCpuUsage }}%</p>
|
||||
</div>
|
||||
<div class="grid-element">
|
||||
<p class="usage" :class="ramUsageFlag(nodeStats.metrics.relativeMemory)">{{ nodeStats.metrics.relativeMemory }}%</p>
|
||||
<p class="usage" :class="ramUsageFlag(node.metrics.relativeMemory)">{{ node.metrics.relativeMemory }}%</p>
|
||||
</div>
|
||||
<div class="grid-element">
|
||||
<p class="usage" :class="diskUsageFlag(nodeStats.metrics.relativeDiskUsage)"><span v-if="nodeStats.metrics.relativeDiskUsage">{{ nodeStats.metrics.relativeDiskUsage }}%</span><span v-else>-</span></p>
|
||||
<p class="usage" :class="diskUsageFlag(node.metrics.relativeDiskUsage)"><span v-if="node.metrics.relativeDiskUsage">{{ node.metrics.relativeDiskUsage }}%</span><span v-else>-</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Node } from '~/classes/node/Node';
|
||||
import NodeReadyComponent from './NodeReadyComponent.vue';
|
||||
import NodeReadyComponent from '../NodeReadyComponent.vue';
|
||||
import { calcAge } from '~/classes/Pod';
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
import NodeViewComponent from "~/components/node/view/NodeViewComponent.vue";
|
||||
|
||||
defineProps<{
|
||||
nodeStats: Node;
|
||||
node: Node;
|
||||
}>();
|
||||
|
||||
function isReady(nodeStats: Node): boolean | undefined
|
||||
function isReady(node: Node): boolean | undefined
|
||||
{
|
||||
const conditions = nodeStats.status.conditions;
|
||||
const conditions = node.status.conditions;
|
||||
if(conditions != undefined)
|
||||
{
|
||||
for(const condition of conditions)
|
||||
96
components/node/view/NodeViewComponent.vue
Normal file
96
components/node/view/NodeViewComponent.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<PopupTemplate :heading="StringUtils.format('Node: %s', node.metadata.name)">
|
||||
<div class="content-l">
|
||||
<h2>General</h2>
|
||||
<div class="content-l">
|
||||
<div class="col-3">
|
||||
<div class="content-m">
|
||||
<h3>Node</h3>
|
||||
<p class="tile-m">{{ node.metadata.name }}</p>
|
||||
</div>
|
||||
<div class="content-m">
|
||||
<h3>Status</h3>
|
||||
<div class="left-center">
|
||||
<NodeReadyComponent :ready="Node.isReady(node)"></NodeReadyComponent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-m">
|
||||
<h3>Metrics</h3>
|
||||
<div class="col-3">
|
||||
<div class="tile-l content-m">
|
||||
<p>Total CPU</p>
|
||||
<p class="metric" v-if="node.metrics.totalCpu != null">{{ (node.metrics.totalCpu / 1000).toFixed(2) }}</p>
|
||||
</div>
|
||||
<div class="tile-l content-m">
|
||||
<p>Total Disk Space</p>
|
||||
<p class="metric" v-if="node.metrics.totalDiskSpace != null" v-for="diskSpace in [Memory.format(node.metrics.totalDiskSpace)]">{{ diskSpace.value.toFixed(2) }} {{ formatUnit(diskSpace.unit) }}</p>
|
||||
</div>
|
||||
<div class="tile-l content-m">
|
||||
<p>Total Memory</p>
|
||||
<p class="metric" v-if="node.metrics.totalMemory != null" v-for="memory in [Memory.format(node.metrics.totalMemory)]">{{ memory.value.toFixed(2) }} {{ formatUnit(memory.unit) }}</p>
|
||||
</div>
|
||||
<div class="tile-l content-m" v-if="node.metrics.relativeCpuUsage">
|
||||
<div class="left-center">
|
||||
<p>Used CPU</p>
|
||||
<Pulse :threshold="new Threshold(node.metrics.relativeCpuUsage, Node.cpuUsageFlag)"></Pulse>
|
||||
</div>
|
||||
<p class="metric">{{ node.metrics.relativeCpuUsage }}%</p>
|
||||
</div>
|
||||
<div class="tile-l content-m" v-if="node.metrics.relativeDiskUsage != null">
|
||||
<div class="left-center">
|
||||
<p>Used Disk Space</p>
|
||||
<Pulse :threshold="new Threshold(node.metrics.relativeDiskUsage, Node.diskUsageFlag)"></Pulse>
|
||||
</div>
|
||||
<p class="metric">{{ node.metrics.relativeDiskUsage }}%</p>
|
||||
</div>
|
||||
<div class="tile-l content-m" v-if="node.metrics.relativeMemory != null">
|
||||
<div class="left-center">
|
||||
<p>Used Memory</p>
|
||||
<Pulse :threshold="new Threshold(node.metrics.relativeMemory, Node.memoryUsageFlag)"></Pulse>
|
||||
</div>
|
||||
<p class="metric">{{ node.metrics.relativeMemory }}%</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-m" v-if="node.spec.taints">
|
||||
<h3>Taints ({{ node.spec.taints.length }})</h3>
|
||||
<div class="content-s">
|
||||
<p class="tile-m" v-for="taint in node.spec.taints">{{ taint.key }}: {{ taint.effect }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="content-m">
|
||||
<h3>Operating System</h3>
|
||||
<p class="tile-m">{{ node.status.nodeInfo.osImage }}</p>
|
||||
</div>
|
||||
<div class="content-m">
|
||||
<h3>Kubelet Version</h3>
|
||||
<p class="tile-m">{{ node.status.nodeInfo.kubeletVersion }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PopupTemplate>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PopupTemplate from "~/components/popup/PopupTemplate.vue";
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
import {Node} from "~/classes/node/Node";
|
||||
import { Memory, MemoryUnity } from '~/utils/Memory';
|
||||
import { Threshold } from '~/classes/Threshold';
|
||||
|
||||
const node = usePopup().data() as Node;
|
||||
|
||||
function formatUnit(unit: MemoryUnity)
|
||||
{
|
||||
return new Map<MemoryUnity, String>([[MemoryUnity.RAW, "Bytes"], [MemoryUnity.KI, "Ki"], [MemoryUnity.MI, "Mi"], [MemoryUnity.GI, "Gi"], [MemoryUnity.TI, "Ti"]]).get(unit);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.metric {
|
||||
font-size: 2rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="grid-element pointer" v-if="pod.metadata" @click="() => showViewPopup = true">{{ pod.metadata.name }}</p>
|
||||
<p class="grid-element pointer" v-if="pod.metadata" @click="usePopup().open(PodViewPopup, props.pod)">{{ pod.metadata.name }}</p>
|
||||
<p class="grid-element" v-if="pod.metadata">{{ pod.metadata.namespace }}</p>
|
||||
<p class="grid-element no-wrap" v-if="pod.metadata">{{ calcAge(pod.metadata.creationTimestamp) }}</p>
|
||||
<p class="grid-element" v-if="pod.spec">{{ pod.spec.nodeName }}</p>
|
||||
@ -10,12 +10,9 @@
|
||||
<PhaseComponent v-if="pod.status" :phase="pod.status.phase"></PhaseComponent>
|
||||
</div>
|
||||
<div class="grid-element action-buttons">
|
||||
<ActionButton @click="showLogPopup = true">text_snippet</ActionButton>
|
||||
<ActionButton @click="showDeletePopup = true">delete</ActionButton>
|
||||
<ActionButton @click="usePopup().open(PodLogPopup, props.pod)">text_snippet</ActionButton>
|
||||
<ActionButton @click="usePopup().open(PodDeletePopup, props.pod)">delete</ActionButton>
|
||||
</div>
|
||||
<PodDeletePopup v-if="showDeletePopup" :pod="pod" @close="showDeletePopup = false"></PodDeletePopup>
|
||||
<PodLogPopup v-if="showLogPopup" :pod="pod" @close="showLogPopup = false"></PodLogPopup>
|
||||
<PodViewPopup v-if="showViewPopup" :pod="pod" @close="showViewPopup = false"></PodViewPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -23,13 +20,11 @@
|
||||
import type { Pod } from '~/classes/Pod';
|
||||
import { calcAge } from '~/classes/Pod';
|
||||
import PodDeletePopup from './view/PodDeletePopup.vue';
|
||||
import PodLogPopup from "~/components/inspect/logs/PodLogPopup.vue";
|
||||
import PodLogPopup from "~/components/pod/view/PodLogPopup.vue";
|
||||
import PodViewPopup from "~/components/pod/view/PodViewPopup.vue";
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
pod: Pod
|
||||
}>();
|
||||
|
||||
const showDeletePopup = ref(false);
|
||||
const showLogPopup = ref(false);
|
||||
const showViewPopup = ref(false);
|
||||
</script>
|
||||
@ -11,7 +11,7 @@
|
||||
<UiMask class="spaced-center" :prefix="env.key" :enabled="isSensitive(env.key)" :value="env.value"></UiMask>
|
||||
</div>
|
||||
<div v-if="error === true">
|
||||
<UiPompt :prompt="new Prompt('This pod does not support retrieving environment variables using \'env\'', PromptType.ERROR)"></UiPompt>
|
||||
<UiPrompt :prompt="new Prompt('This pod does not support retrieving environment variables using \'env\'', PromptType.ERROR)"></UiPrompt>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollComponent>
|
||||
@ -19,12 +19,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Prompt, PromptType } from '~/components/ui/prompt/Prompt';
|
||||
import type { Container, Pod } from '~/classes/Pod';
|
||||
import { EnvVar } from '../env/EnvVar';
|
||||
import {EnvVar} from "~/components/pod/env/EnvVar";
|
||||
import ContainerPicker from '~/components/ui/ContainerPicker.vue';
|
||||
import UiMask from '~/components/ui/UiMask.vue';
|
||||
import { Prompt, PromptType } from '~/components/ui/Prompt';
|
||||
import UiPompt from '~/components/ui/UiPompt.vue';
|
||||
import UiPrompt from '~/components/ui/prompt/UiPrompt.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
pod: Pod
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<PopupTemplate size="SMALL" heading="Delete Pod" @close="emits('close')">
|
||||
<PopupTemplate size="SMALL" heading="Delete Pod">
|
||||
<div class="content-l">
|
||||
<div class="content-m">
|
||||
<div class="tile-m">
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<UiButton :loading="loading" class="width-6rem hollow">Cancel</UiButton>
|
||||
<UiButton :loading="loading" class="width-6rem hollow" @click="usePopup().close()">Cancel</UiButton>
|
||||
<UiButton :loading="loading" class="width-6rem" icon="delete" reverse :onclick="() => del()">Delete</UiButton>
|
||||
</div>
|
||||
</div>
|
||||
@ -23,24 +23,19 @@
|
||||
import type { Metadata } from '~/classes/Metadata';
|
||||
import { type Pod } from '~/classes/Pod';
|
||||
import { deletePod } from '~/requests/pod';
|
||||
import { usePopup } from "~/components/popup/Popup";
|
||||
|
||||
const props = defineProps<{
|
||||
pod: Pod
|
||||
}>();
|
||||
const pod = usePopup().data() as Pod;
|
||||
|
||||
const loading = ref(false);
|
||||
function del()
|
||||
{
|
||||
const metadata: Metadata = props.pod.metadata;
|
||||
loading.value = true;
|
||||
const metadata: Metadata = pod.metadata;
|
||||
deletePod(metadata.namespace, metadata.name, () => {
|
||||
emits('close');
|
||||
usePopup().close();
|
||||
});
|
||||
}
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -16,9 +16,10 @@
|
||||
import { LogRepo } from '~/classes/LogRepo';
|
||||
import type { Pod } from '~/classes/Pod';
|
||||
import { Log } from '~/requests/logs';
|
||||
import Console from "~/components/inspect/logs/Console.vue";
|
||||
import Console from "~/components/inspect/console/Console.vue";
|
||||
import UiIcon from "~/components/ui/UiIcon.vue";
|
||||
import { ConsoleConfig } from '~/components/inspect/logs/ConsoleConfig'
|
||||
import { ConsoleConfig } from '~/components/inspect/console/ConsoleConfig'
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
const config = ref(ConsoleConfig.default(true, false, false));
|
||||
|
||||
@ -26,9 +27,7 @@ const base = ref();
|
||||
|
||||
const logs: Ref<Log[]> = ref([]);
|
||||
|
||||
const props = defineProps<{
|
||||
pod: Pod
|
||||
}>();
|
||||
const pod = usePopup().data() as Pod;
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
@ -36,7 +35,7 @@ const emits = defineEmits<{
|
||||
|
||||
const logRepo = new LogRepo();
|
||||
onMounted(() => {
|
||||
logRepo.listen("pods", props.pod.metadata.namespace, props.pod.metadata.name,(_logs: Log[]) => {
|
||||
logRepo.listen("pods", pod.metadata.namespace, pod.metadata.name,(_logs: Log[]) => {
|
||||
logs.value.push(..._logs);
|
||||
});
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<PopupTemplate ref="base" :heading="StringUtils.format('%s/%s', pod.metadata.namespace, pod.metadata.name)" @close="emits('close')">
|
||||
<PopupTemplate ref="base" :heading="StringUtils.format('%s/%s', pod.metadata.namespace, pod.metadata.name)">
|
||||
<div class="col-2 expand">
|
||||
<ScrollComponent>
|
||||
<div class="content-l">
|
||||
@ -54,29 +54,7 @@ import { calcAge, type Pod } from '~/classes/Pod';
|
||||
import PhaseComponent from '~/components/PhaseComponent.vue';
|
||||
import ScrollComponent from '~/components/ScrollComponent.vue';
|
||||
import EnvironmentViewer from './EnvironmentViewer.vue';
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
const base = ref();
|
||||
|
||||
const props = defineProps<{
|
||||
pod: Pod
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
}>()
|
||||
|
||||
function open() {
|
||||
base.value.open();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if(event.key === 'Escape')
|
||||
{
|
||||
base.value.close();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
defineExpose({ open });
|
||||
const pod = usePopup().data() as Pod;
|
||||
</script>
|
||||
54
components/popup/Popup.ts
Normal file
54
components/popup/Popup.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import type {DefineComponent} from "vue";
|
||||
|
||||
export const usePopup = defineStore('popup', {
|
||||
state: () => ({
|
||||
component: shallowRef<DefineComponent<any, any, any> | undefined>(undefined),
|
||||
payload: undefined as any,
|
||||
isOpen: false as boolean
|
||||
}),
|
||||
getters: {
|
||||
data(): any {
|
||||
return () => {
|
||||
return this.payload;
|
||||
}
|
||||
},
|
||||
get: (state) => {
|
||||
return () => {
|
||||
return state.component;
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
open(component: DefineComponent<any, any, any>, payload?: any) {
|
||||
this.component = component;
|
||||
this.payload = payload;
|
||||
this.isOpen = true
|
||||
disableScrolling();
|
||||
},
|
||||
close() {
|
||||
this.component = undefined;
|
||||
this.payload = undefined;
|
||||
this.isOpen = false;
|
||||
enableScrolling();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function disableScrolling()
|
||||
{
|
||||
const body = document.getElementsByTagName('body');
|
||||
for(const element of body)
|
||||
{
|
||||
element.style.overflow = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
function enableScrolling()
|
||||
{
|
||||
const body = document.getElementsByTagName('body');
|
||||
for(const element of body)
|
||||
{
|
||||
element.style.overflow = "visible";
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="overlay center" @click="close" v-show="visible || true">
|
||||
<div class="overlay center" @click="usePopup().close()">
|
||||
<div class="popup" :class="size" @click.stop>
|
||||
<div class="popup__header">
|
||||
<h2>{{ heading }}</h2>
|
||||
<UiButton icon="close" @click="() => close()" class="square"></UiButton>
|
||||
<UiButton icon="close" @click="usePopup().close()" class="square"></UiButton>
|
||||
</div>
|
||||
<div class="popup__body">
|
||||
<slot></slot>
|
||||
@ -13,50 +13,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const visible = ref(false);
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'close'): void
|
||||
}>()
|
||||
|
||||
function close() {
|
||||
enableScrolling();
|
||||
emits('close');
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function open() {
|
||||
disableScrolling();
|
||||
visible.value = true;
|
||||
}
|
||||
import {usePopup} from "~/components/popup/Popup";
|
||||
|
||||
defineProps({
|
||||
heading: String,
|
||||
size: String
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
close,
|
||||
open
|
||||
})
|
||||
|
||||
function disableScrolling()
|
||||
{
|
||||
const body = document.getElementsByTagName('body');
|
||||
for(const element of body)
|
||||
{
|
||||
element.style.overflow = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
function enableScrolling()
|
||||
{
|
||||
const body = document.getElementsByTagName('body');
|
||||
for(const element of body)
|
||||
{
|
||||
element.style.overflow = "visible";
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if(event.key === 'Escape')
|
||||
{
|
||||
usePopup().close();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -69,7 +38,6 @@ function enableScrolling()
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,6 @@ const emits = defineEmits<{
|
||||
watch(selected, (selection) => {
|
||||
if (selection != null)
|
||||
{
|
||||
console.log("X");
|
||||
emits('selected', selection);
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
@ -1,32 +1,42 @@
|
||||
<template>
|
||||
<PodComponent v-if="resource === 'pods'"></PodComponent>
|
||||
<CustomResourceDefinitionComponent v-else-if="resource === 'custom-resource-definitions'"></CustomResourceDefinitionComponent>
|
||||
<IngressComponent v-else-if="resource === 'ingresses'"></IngressComponent>
|
||||
<ServiceComponent v-else-if="resource === 'services'"></ServiceComponent>
|
||||
<DeploymentList v-else-if="resource === 'deployments'"></DeploymentList>
|
||||
<NodeComponent v-else-if="resource === 'nodes'"></NodeComponent>
|
||||
<SecretComponent v-else-if="resource === 'secrets'"></SecretComponent>
|
||||
<ConfigMapList v-else-if="resource === 'config-maps'"></ConfigMapList>
|
||||
<StatefulSetList v-else-if="resource === 'stateful-sets'"></StatefulSetList>
|
||||
<PersistentVolumeList v-else-if="resource === 'pvs'"></PersistentVolumeList>
|
||||
<PersistentVolumeClaimList v-else-if="resource === 'pvcs'"></PersistentVolumeClaimList>
|
||||
<NamespaceList v-else-if="resource === 'namespaces'"></NamespaceList>
|
||||
<Component v-if="components[resource]" :is="components[resource]"></Component>
|
||||
<p v-else>Invalid resource</p>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PodComponent from '~/components/inspect/resources/PodList.vue';
|
||||
import CustomResourceDefinitionComponent from '~/components/inspect/resources/CustomResourceDefinitionList.vue';
|
||||
import IngressComponent from '~/components/inspect/resources/IngressList.vue';
|
||||
import ServiceComponent from '~/components/inspect/resources/ServiceList.vue';
|
||||
import PodList from '~/components/inspect/resources/PodList.vue';
|
||||
import CustomResourceDefinitionList from '~/components/inspect/resources/CustomResourceDefinitionList.vue';
|
||||
import IngressList from '~/components/inspect/resources/IngressList.vue';
|
||||
import ServiceList from '~/components/inspect/resources/ServiceList.vue';
|
||||
import DeploymentList from "~/components/inspect/resources/DeploymentList.vue";
|
||||
import NodeComponent from '~/components/inspect/resources/NodeList.vue';
|
||||
import SecretComponent from '~/components/inspect/resources/SecretList.vue';
|
||||
import NodeList from '~/components/inspect/resources/NodeList.vue';
|
||||
import SecretList from '~/components/inspect/resources/SecretList.vue';
|
||||
import ConfigMapList from '~/components/inspect/resources/ConfigMapList.vue';
|
||||
import StatefulSetList from '~/components/inspect/resources/StatefulSetList.vue';
|
||||
import PersistentVolumeList from '~/components/inspect/resources/PersistentVolumeList.vue';
|
||||
import PersistentVolumeClaimList from '~/components/inspect/resources/PersistentVolumeClaimList.vue';
|
||||
import NamespaceList from '~/components/inspect/resources/NamespaceList.vue';
|
||||
import type { Component } from "vue";
|
||||
import {ResourceType} from "~/components/inspect/ResourceType";
|
||||
|
||||
const resource = useRoute().params.resource as string;
|
||||
const resource = useRoute().params.resource as ResourceType;
|
||||
|
||||
const components: Record<ResourceType, Component> = {
|
||||
[ResourceType.NODE]: NodeList,
|
||||
[ResourceType.NAMESPACE]: NamespaceList,
|
||||
[ResourceType.CUSTOM_RESOURCE_DEFINITION]: CustomResourceDefinitionList,
|
||||
|
||||
[ResourceType.POD]: PodList,
|
||||
[ResourceType.DEPLOYMENT]: DeploymentList,
|
||||
[ResourceType.STATEFUL_SET]: StatefulSetList,
|
||||
|
||||
[ResourceType.SERVICE]: ServiceList,
|
||||
[ResourceType.INGRESS]: IngressList,
|
||||
|
||||
[ResourceType.SECRET]: SecretList,
|
||||
[ResourceType.CONFIG_MAP]: ConfigMapList,
|
||||
|
||||
[ResourceType.PV]: PersistentVolumeList,
|
||||
[ResourceType.PVC]: PersistentVolumeClaimList,
|
||||
};
|
||||
</script>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="content-l">
|
||||
<h2>Change Password</h2>
|
||||
<UiPompt :prompt="prompt" @close="prompt = undefined"></UiPompt>
|
||||
<UiPrompt :prompt="prompt" @close="prompt = undefined"></UiPrompt>
|
||||
<div class="col-2 tile-l">
|
||||
<UiInput label="New Password" required>
|
||||
<input type="password" v-model="password">
|
||||
@ -17,9 +17,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Prompt, PromptType } from '~/components/ui/Prompt';
|
||||
import { Prompt, PromptType } from '~/components/ui/prompt/Prompt';
|
||||
import { changePassword } from '~/requests/user';
|
||||
import UiPompt from '~/components/ui/UiPompt.vue';
|
||||
import UiPrompt from '~/components/ui/prompt/UiPrompt.vue';
|
||||
|
||||
const password = ref('');
|
||||
const repeatPassword = ref('');
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<div class="content-l">
|
||||
<h2 class="center">Kubooboo</h2>
|
||||
<div class="center">
|
||||
<img class="logo" src="@/assets/transparent_logo.png" alt=""></img>
|
||||
<img class="logo" src="@/assets/transparent_logo.png" alt="">
|
||||
</div>
|
||||
<div class="center">
|
||||
<h1>Login</h1>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { Node } from "~/classes/Node";
|
||||
import {Node} from "~/classes/node/Node";
|
||||
|
||||
export function getNodes(onSuccess: (nodes: Node[]) => void)
|
||||
{
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
import type {DefineComponent} from "vue";
|
||||
|
||||
export const usePopup = defineStore('namespace', {
|
||||
state: () => ({
|
||||
component: undefined as DefineComponent | undefined,
|
||||
data: undefined as any,
|
||||
isOpen: false as boolean
|
||||
}),
|
||||
getters: {
|
||||
|
||||
},
|
||||
actions: {
|
||||
open(component: DefineComponent, data?: any) {
|
||||
this.component = component;
|
||||
this.data = data;
|
||||
this.isOpen = true;
|
||||
},
|
||||
close() {
|
||||
this.component = undefined;
|
||||
this.data = undefined;
|
||||
this.isOpen = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
23
utils/Memory.ts
Normal file
23
utils/Memory.ts
Normal file
@ -0,0 +1,23 @@
|
||||
export class Memory
|
||||
{
|
||||
constructor (
|
||||
public value: number,
|
||||
public unit: MemoryUnity
|
||||
) {}
|
||||
|
||||
static format(input: number)
|
||||
{
|
||||
let dimension: number = 0;
|
||||
while (input > 1024)
|
||||
{
|
||||
input = input / 1024;
|
||||
dimension++;
|
||||
}
|
||||
return new Memory(input, dimension as MemoryUnity);
|
||||
}
|
||||
}
|
||||
|
||||
export enum MemoryUnity
|
||||
{
|
||||
RAW, KI, MI, GI, TI
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user