🚸 Improve Console

This commit is contained in:
Andreas Dinauer 2025-12-25 13:38:25 +01:00
parent 84b2c105d1
commit 0d0fbab605
9 changed files with 60 additions and 94 deletions

View File

@ -22,6 +22,22 @@ html * {
color: black; color: black;
} }
html a.external {
color: #24a4ff;
}
html .marked.green {
color: #24ff24;
}
html .marked.yellow {
color: #ffa32b;
}
html .marked.red {
color: #ff362f;
}
html, body, #__nuxt { html, body, #__nuxt {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;

View File

@ -4,14 +4,13 @@ export class LogRepo
{ {
websocket?: WebSocket = undefined; websocket?: WebSocket = undefined;
listen(namespace: string, name: string, onReceive: (logs: Log[]) => void) listen(resourceType: string, namespace: string, name: string, onReceive: (logs: Log[]) => void)
{ {
const websocket = new WebSocket(StringUtils.format("%s/logs/%s/%s", ApiConfig.getWsBase(), namespace, name)); const websocket = new WebSocket(StringUtils.format("%s/logs/%s/%s/%s", ApiConfig.getWsBase(), resourceType, namespace, name));
websocket.addEventListener('open', () => { websocket.addEventListener('open', () => {
console.info("Opened Websocket."); console.info("Opened Websocket.");
}) })
websocket.addEventListener("message", (event) => { websocket.addEventListener("message", (event) => {
console.log(event.data);
onReceive(JSON.parse(event.data) as Log[]); onReceive(JSON.parse(event.data) as Log[]);
}); });
const interval = setInterval(() => { const interval = setInterval(() => {

View File

@ -2,16 +2,27 @@ import dayjs from "dayjs";
import advancedFormat from "dayjs/plugin/advancedFormat"; import advancedFormat from "dayjs/plugin/advancedFormat";
import type { Metadata } from "./Metadata"; import type { Metadata } from "./Metadata";
import type { HasMetadata } from "./repo/ResourceRepo"; import type { HasMetadata } from "./repo/ResourceRepo";
import axios from "axios";
export class Pod implements HasMetadata export class Pod implements HasMetadata
{ {
constructor ( constructor (
public metadata: Metadata, public metadata: Metadata,
public spec: Spec, public spec: Spec,
public status: Status public status: Status
) { } ) { }
static getByDeployment(namespace: string, name: string, onSuccess: (pods: Pod[]) => void)
{
axios.get<Pod[]>(StringUtils.format('%s/resources/deployments/%s/%s/pods', ApiConfig.getHttpBase(), namespace, name), {
headers: {
Authorization: "Bearer " + requireToken()
}
})
.then((response) => {
onSuccess(response.data)
});
}
} }
class Spec { class Spec {

View File

@ -1,88 +0,0 @@
<template>
<PopupTemplate :heading="'Logs: ' + pod.metadata?.namespace + '/' + pod.metadata?.name" ref="base" @close="emits('close')">
<ScrollComponent ref="scrollComponent" v-show="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>
</div>
</ScrollComponent>
<div v-if="logs == null" class="center" style="height: 100%; width: 100%">
<UiLoadingIcon size="2rem"></UiLoadingIcon>
</div>
<p>{{ logs }}</p>
</PopupTemplate>
</template>
<script setup lang="ts">
import dayjs from 'dayjs';
import { LogRepo } from '~/classes/LogRepo';
import type { Pod } from '~/classes/Pod';
import { getLogs } from '~/requests/logs';
import { Log } from '~/requests/logs';
const base = ref();
const logs: Ref<Log[]> = ref([]);
const props = defineProps<{
pod: Pod
}>();
const emits = defineEmits<{
(e: 'close'): void
}>()
function close() {
}
const scrollComponent = ref();
const logRepo = new LogRepo();
onMounted(() => {
logRepo.listen( props.pod.metadata.namespace, props.pod.metadata.name,(_logs: Log[]) => {
logs.value.push(..._logs);
scrollComponent.value.scrollToBottom();
});
});
onUnmounted(() => {
logRepo.clear();
});
onMounted(() => {
document.addEventListener('keydown', (event) => {
if(event.key === 'Escape')
{
emits('close');
}
});
})
</script>
<style scoped>
.log {
display: grid;
grid-template-columns: auto 1fr;
padding: 0.125rem 1rem;
gap: 1rem;
}
.log * {
width: 100%;
max-width: 100%;
word-break: break-all;
white-space: pre-wrap;
color: white;
line-height: 1.15rem;
font-weight: 600;
}
.console {
background-color: black;
border-radius: 0.5rem;
display: grid;
padding: 1rem 0;
align-content: start;
}
.even {
background-color: rgb(24, 24, 24);
}
</style>

View File

@ -15,6 +15,7 @@ function scrollToBottom()
const element = document.getElementById(id); const element = document.getElementById(id);
if(element) if(element)
{ {
console.log("Scroll to bottom");
element.scrollTo({top: element.scrollHeight, behavior: 'instant'}); element.scrollTo({top: element.scrollHeight, behavior: 'instant'});
} }
}) })

View File

@ -5,11 +5,13 @@
<p class="grid-element">{{ calcAge(deployment.metadata.creationTimestamp) }}</p> <p class="grid-element">{{ calcAge(deployment.metadata.creationTimestamp) }}</p>
<p class="grid-element">{{ deployment.spec.replicas }}</p> <p class="grid-element">{{ deployment.spec.replicas }}</p>
<div class="grid-element action-buttons"> <div class="grid-element action-buttons">
<ActionButton @click="() => showLogsPopup = true">text_snippet</ActionButton>
<ActionButton>autorenew</ActionButton> <ActionButton>autorenew</ActionButton>
<ActionButton @click="() => rescaleDeploymentPopup.open()">height</ActionButton> <ActionButton @click="() => rescaleDeploymentPopup.open()">height</ActionButton>
</div> </div>
<RescaleDeploymentPopup ref="rescaleDeploymentPopup" :deployment="deployment"></RescaleDeploymentPopup> <RescaleDeploymentPopup ref="rescaleDeploymentPopup" :deployment="deployment"></RescaleDeploymentPopup>
<DeploymentViewPopup v-if="showViewPopup" :deployment="deployment" @close="() => showViewPopup = false"></DeploymentViewPopup> <DeploymentViewPopup v-if="showViewPopup" :deployment="deployment" @close="() => showViewPopup = false"></DeploymentViewPopup>
<DeploymentLogPopup v-if="showLogsPopup" :deployment="deployment" @close="() => showLogsPopup = false"></DeploymentLogPopup>
</div> </div>
</template> </template>
@ -18,6 +20,7 @@ import { Deployment } from '~/classes/Deployment';
import { calcAge } from '~/classes/Pod'; import { calcAge } from '~/classes/Pod';
import RescaleDeploymentPopup from '../RescaleDeploymentPopup.vue'; import RescaleDeploymentPopup from '../RescaleDeploymentPopup.vue';
import DeploymentViewPopup from "~/components/deployment/view/DeploymentViewPopup.vue"; import DeploymentViewPopup from "~/components/deployment/view/DeploymentViewPopup.vue";
import DeploymentLogPopup from "~/components/inspect/logs/DeploymentLogPopup.vue";
defineProps<{ defineProps<{
deployment: Deployment deployment: Deployment
@ -25,4 +28,5 @@ defineProps<{
const rescaleDeploymentPopup = ref(); const rescaleDeploymentPopup = ref();
const showViewPopup = ref(false); const showViewPopup = ref(false);
const showLogsPopup = ref(false);
</script> </script>

View File

@ -14,7 +14,7 @@
<ActionButton @click="showDeletePopup = true">delete</ActionButton> <ActionButton @click="showDeletePopup = true">delete</ActionButton>
</div> </div>
<PodDeletePopup v-if="showDeletePopup" :pod="pod" @close="showDeletePopup = false"></PodDeletePopup> <PodDeletePopup v-if="showDeletePopup" :pod="pod" @close="showDeletePopup = false"></PodDeletePopup>
<LogPopup v-if="showLogPopup" :pod="pod" @close="showLogPopup = false"></LogPopup> <PodLogPopup v-if="showLogPopup" :pod="pod" @close="showLogPopup = false"></PodLogPopup>
<PodViewPopup v-if="showViewPopup" :pod="pod" @close="showViewPopup = false"></PodViewPopup> <PodViewPopup v-if="showViewPopup" :pod="pod" @close="showViewPopup = false"></PodViewPopup>
</div> </div>
</template> </template>
@ -23,6 +23,7 @@
import type { Pod } from '~/classes/Pod'; import type { Pod } from '~/classes/Pod';
import { calcAge } from '~/classes/Pod'; import { calcAge } from '~/classes/Pod';
import PodDeletePopup from './view/PodDeletePopup.vue'; import PodDeletePopup from './view/PodDeletePopup.vue';
import PodLogPopup from "~/components/inspect/logs/PodLogPopup.vue";
defineProps<{ defineProps<{
pod: Pod pod: Pod

View File

@ -0,0 +1,21 @@
<template>
<div class="pod-picker base-shape">
<div v-for="pod in pods">
<p>{{ pod.metadata.name }}</p>
</div>
</div>
</template>
<script setup lang="ts">
import type {Pod} from "~/classes/Pod";
defineProps<{
pods: Pod[]
}>()
</script>
<style scoped>
.pod-picker {
background-color: var(--tile-color);
}
</style>

View File

@ -3,6 +3,7 @@ import axios from "axios";
export class Log export class Log
{ {
constructor ( constructor (
public podName: string,
public timestamp: string, public timestamp: string,
public message: string public message: string
) {} ) {}