💄 Improved UI
This commit is contained in:
parent
e3ff52b020
commit
7b05306369
@ -58,6 +58,8 @@ html, body, #__nuxt {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #f3f3f3;
|
background-color: #f3f3f3;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
height: 2rem;
|
||||||
}
|
}
|
||||||
.resource:hover > .grid-element {
|
.resource:hover > .grid-element {
|
||||||
background-color: #dbdbdb;
|
background-color: #dbdbdb;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 227 KiB |
@ -1,9 +1,10 @@
|
|||||||
import type { Metadata } from "./Metadata";
|
import type { Metadata } from "./Metadata";
|
||||||
|
import type { HasMetadata } from "./repo/ResourceRepo";
|
||||||
|
|
||||||
export class ConfigMap
|
export class ConfigMap implements HasMetadata
|
||||||
{
|
{
|
||||||
constructor (
|
constructor (
|
||||||
public metadata: Metadata,
|
public metadata: Metadata,
|
||||||
public data: Record<string, string>
|
public data?: Record<string, string>
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "./Metadata";
|
import type { Metadata } from "./Metadata";
|
||||||
import type { HasMetadata } from "./ResourceRepo";
|
import type { HasMetadata } from "./repo/ResourceRepo";
|
||||||
|
|
||||||
export class Node implements HasMetadata
|
export class Node implements HasMetadata
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import dayjs from "dayjs";
|
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 "./ResourceRepo";
|
import type { HasMetadata } from "./repo/ResourceRepo";
|
||||||
|
|
||||||
export class Pod implements HasMetadata
|
export class Pod implements HasMetadata
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,140 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
import type { Metadata } from "./Metadata";
|
|
||||||
|
|
||||||
export interface HasMetadata {
|
|
||||||
metadata: Metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ResourceEvent<T extends HasMetadata>
|
|
||||||
{
|
|
||||||
constructor (
|
|
||||||
public type: string,
|
|
||||||
public resources: T[]
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ResourceRepo<T extends HasMetadata>
|
|
||||||
{
|
|
||||||
private resources: Ref<T[]> = ref([]);
|
|
||||||
private interval: NodeJS.Timeout | undefined = undefined;
|
|
||||||
private websocket: WebSocket | undefined = undefined;
|
|
||||||
|
|
||||||
static init<T extends HasMetadata>()
|
|
||||||
{
|
|
||||||
return new ResourceRepo<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
listen(resource: string)
|
|
||||||
{
|
|
||||||
const websocket = new WebSocket(StringUtils.format("%s/watch/%s/%s", ApiConfig.getWsBase(), resource, this.getNamespace()));
|
|
||||||
websocket.addEventListener('open', () => {
|
|
||||||
console.info("Opened Websocket.");
|
|
||||||
})
|
|
||||||
websocket.addEventListener("message", (event) => {
|
|
||||||
const data = JSON.parse(event.data) as ResourceEvent<T>;
|
|
||||||
console.info(StringUtils.format("[%s] Resource", data.type));
|
|
||||||
switch (data.type)
|
|
||||||
{
|
|
||||||
case "INIT":
|
|
||||||
{
|
|
||||||
this.add(data.resources);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "ADDED":
|
|
||||||
{
|
|
||||||
this.add(data.resources);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "MODIFIED":
|
|
||||||
{
|
|
||||||
this.update(data.resources);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "DELETED":
|
|
||||||
{
|
|
||||||
this.delete(data.resources);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
console.info("[PING]");
|
|
||||||
websocket.send('[PING]');
|
|
||||||
}, 5000);
|
|
||||||
websocket.addEventListener("close", () => {
|
|
||||||
console.info("Closing websocket.");
|
|
||||||
clearTimeout(interval);
|
|
||||||
});
|
|
||||||
this.websocket = websocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
private add(resources: T[])
|
|
||||||
{
|
|
||||||
this.resources.value.push(...resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
private delete(resources: T[])
|
|
||||||
{
|
|
||||||
for (const resource of resources)
|
|
||||||
{
|
|
||||||
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
|
|
||||||
if (index != null)
|
|
||||||
{
|
|
||||||
this.resources.value.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private update(resources: T[])
|
|
||||||
{
|
|
||||||
for (const resource of resources)
|
|
||||||
{
|
|
||||||
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
|
|
||||||
if (index != null)
|
|
||||||
{
|
|
||||||
this.resources.value[index] = resource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
load(resourceType: string)
|
|
||||||
{
|
|
||||||
this.refresh(resourceType);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear()
|
|
||||||
{
|
|
||||||
clearTimeout(this.interval);
|
|
||||||
if (this.websocket != null)
|
|
||||||
{
|
|
||||||
this.websocket.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get()
|
|
||||||
{
|
|
||||||
return computed(() => {
|
|
||||||
return this.resources.value.toSorted((a, b) => a.metadata.name.localeCompare(b.metadata.name));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private refresh(resourceType: string)
|
|
||||||
{
|
|
||||||
const namespace = this.getNamespace();
|
|
||||||
let url = StringUtils.format("%s/resources/%s", ApiConfig.getHttpBase(), resourceType);
|
|
||||||
if (namespace)
|
|
||||||
{
|
|
||||||
url = StringUtils.format("%s/%s", url, namespace);
|
|
||||||
}
|
|
||||||
axios.get<T[]>(url)
|
|
||||||
.then((response) => {
|
|
||||||
this.resources.value = response.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private getNamespace()
|
|
||||||
{
|
|
||||||
return useRoute().params.namespace as string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { Metadata } from "./Metadata";
|
import { Metadata } from "./Metadata";
|
||||||
import type { HasMetadata } from "./ResourceRepo";
|
import type { HasMetadata } from "./repo/ResourceRepo";
|
||||||
|
|
||||||
export class Secret implements HasMetadata
|
export class Secret implements HasMetadata
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "./Metadata";
|
import type { Metadata } from "./Metadata";
|
||||||
import type { HasMetadata } from "./ResourceRepo";
|
import type { HasMetadata } from "./repo/ResourceRepo";
|
||||||
|
|
||||||
export class Service implements HasMetadata
|
export class Service implements HasMetadata
|
||||||
{
|
{
|
||||||
|
|||||||
24
classes/repo/AdvancedWebSocket.ts
Normal file
24
classes/repo/AdvancedWebSocket.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export class AdvancedWebSocket
|
||||||
|
{
|
||||||
|
constructor (
|
||||||
|
private websocket: WebSocket,
|
||||||
|
private timeout: NodeJS.Timeout
|
||||||
|
) {}
|
||||||
|
|
||||||
|
static open(url: string, onMessage: (event: MessageEvent) => void, onClose: (event: CloseEvent) => void)
|
||||||
|
{
|
||||||
|
const websocket = new WebSocket(url);
|
||||||
|
websocket.addEventListener('message', onMessage);
|
||||||
|
websocket.addEventListener('close', onClose);
|
||||||
|
const timeout = setInterval(() => {
|
||||||
|
websocket.send("[PING]");
|
||||||
|
}, 5000);
|
||||||
|
return new AdvancedWebSocket(websocket, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
close()
|
||||||
|
{
|
||||||
|
this.websocket.close();
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
classes/repo/ResourceEventType.ts
Normal file
7
classes/repo/ResourceEventType.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export enum ResourceEventType
|
||||||
|
{
|
||||||
|
INIT = "INIT",
|
||||||
|
ADDED = "ADDED",
|
||||||
|
MODIFIED = "MODIFIED",
|
||||||
|
DELETED = "DELETED"
|
||||||
|
}
|
||||||
149
classes/repo/ResourceRepo.ts
Normal file
149
classes/repo/ResourceRepo.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import type { Metadata } from "../Metadata";
|
||||||
|
import { ResourceEventType } from "./ResourceEventType";
|
||||||
|
import { AdvancedWebSocket } from "./AdvancedWebSocket";
|
||||||
|
import { WebsocketSession } from "./WebsocketSession";
|
||||||
|
|
||||||
|
export interface HasMetadata {
|
||||||
|
metadata: Metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResourceEvent<T extends HasMetadata>
|
||||||
|
{
|
||||||
|
constructor (
|
||||||
|
public type: ResourceEventType,
|
||||||
|
public resources: T[]
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResourceRepo<T extends HasMetadata>
|
||||||
|
{
|
||||||
|
private resources: Ref<T[] | undefined> = ref(undefined);
|
||||||
|
private websocket?: AdvancedWebSocket;
|
||||||
|
|
||||||
|
static init<T extends HasMetadata>()
|
||||||
|
{
|
||||||
|
return new ResourceRepo<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(resource: string)
|
||||||
|
{
|
||||||
|
WebsocketSession.get((token: string) => {
|
||||||
|
const webSocket = AdvancedWebSocket.open(StringUtils.format("%s/watch/%s/%s?token=%s", ApiConfig.getWsBase(), resource, this.getNamespace(), token),
|
||||||
|
(event) => {
|
||||||
|
const data = JSON.parse(event.data) as ResourceEvent<T>;
|
||||||
|
switch (data.type)
|
||||||
|
{
|
||||||
|
case ResourceEventType.INIT:
|
||||||
|
{
|
||||||
|
this.add(data.resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ResourceEventType.ADDED:
|
||||||
|
{
|
||||||
|
this.add(data.resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ResourceEventType.MODIFIED:
|
||||||
|
{
|
||||||
|
this.update(data.resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ResourceEventType.DELETED:
|
||||||
|
{
|
||||||
|
this.delete(data.resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => { }
|
||||||
|
);
|
||||||
|
this.websocket = webSocket;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private add(resources: T[])
|
||||||
|
{
|
||||||
|
if (this.resources.value == null)
|
||||||
|
{
|
||||||
|
this.resources.value = [];
|
||||||
|
}
|
||||||
|
this.resources.value.push(...resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
private delete(resources: T[])
|
||||||
|
{
|
||||||
|
if (this.resources.value == null)
|
||||||
|
{
|
||||||
|
this.resources.value = [];
|
||||||
|
}
|
||||||
|
for (const resource of resources)
|
||||||
|
{
|
||||||
|
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
|
||||||
|
if (index != null)
|
||||||
|
{
|
||||||
|
this.resources.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(resources: T[])
|
||||||
|
{
|
||||||
|
if (this.resources.value == null)
|
||||||
|
{
|
||||||
|
this.resources.value = [];
|
||||||
|
}
|
||||||
|
for (const resource of resources)
|
||||||
|
{
|
||||||
|
const index = this.resources.value.findIndex(item => item.metadata.uid === resource.metadata.uid);
|
||||||
|
if (index != null)
|
||||||
|
{
|
||||||
|
this.resources.value[index] = resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load(resourceType: string)
|
||||||
|
{
|
||||||
|
this.refresh(resourceType);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear()
|
||||||
|
{
|
||||||
|
if (this.websocket)
|
||||||
|
{
|
||||||
|
this.websocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
return computed(() => {
|
||||||
|
if (this.resources.value)
|
||||||
|
{
|
||||||
|
return this.resources.value.toSorted((a, b) => a.metadata.name.localeCompare(b.metadata.name));
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private refresh(resourceType: string)
|
||||||
|
{
|
||||||
|
const namespace = this.getNamespace();
|
||||||
|
let url = StringUtils.format("%s/resources/%s", ApiConfig.getHttpBase(), resourceType);
|
||||||
|
if (namespace)
|
||||||
|
{
|
||||||
|
url = StringUtils.format("%s/%s", url, namespace);
|
||||||
|
}
|
||||||
|
axios.get<T[]>(url)
|
||||||
|
.then((response) => {
|
||||||
|
this.resources.value = response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNamespace()
|
||||||
|
{
|
||||||
|
return useRoute().params.namespace as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
classes/repo/WebsocketSession.ts
Normal file
16
classes/repo/WebsocketSession.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export class WebsocketSession
|
||||||
|
{
|
||||||
|
static get(onSucces: (token: string) => void)
|
||||||
|
{
|
||||||
|
axios.post<string>(ApiConfig.getHttpBase() + '/websocket-session', undefined, {
|
||||||
|
headers: {
|
||||||
|
Authorization: StringUtils.format("Bearer %s", requireToken())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
onSucces(response.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,16 +2,15 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="grid-element">{{ configMap.metadata.name }}</p>
|
<p class="grid-element">{{ configMap.metadata.name }}</p>
|
||||||
<p class="grid-element">{{ configMap.metadata.namespace }}</p>
|
<p class="grid-element">{{ configMap.metadata.namespace }}</p>
|
||||||
<p class="grid-element">{{ Object.keys(configMap.data).length }}</p>
|
<p class="grid-element"><span v-if="configMap.data">{{ Object.keys(configMap.data).length }}</span><span v-else>-</span></p>
|
||||||
<div class="grid-element">
|
<div class="grid-element">
|
||||||
<ActionButton v-if="hasAnyRole(getUser(), ['admin', 'maintainer'])">delete</ActionButton>
|
<ActionButton>delete</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ConfigMap } from '~/classes/ConfigMap';
|
import type { ConfigMap } from '~/classes/ConfigMap';
|
||||||
import { hasAnyRole } from '~/classes/User';
|
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
configMap: ConfigMap
|
configMap: ConfigMap
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<SidebarTemplate>
|
<SidebarTemplate>
|
||||||
<div class="content-l" style="display: grid; grid-template-rows: auto 1fr; height: 100%;">
|
|
||||||
<h2>Kubooboo</h2>
|
|
||||||
<ScrollComponent>
|
<ScrollComponent>
|
||||||
<div class="content-l">
|
<div class="content-l">
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
@ -13,8 +11,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ScrollComponent>
|
</ScrollComponent>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="left-center" v-if="user" @click="() => accountPopup.open()">
|
<div class="left-center" v-if="user" @click="() => accountPopup.open()">
|
||||||
<UiIcon>account_circle</UiIcon>
|
<UiIcon>account_circle</UiIcon>
|
||||||
<p>{{ user.username }}</p>
|
<p>{{ user.username }}</p>
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.router-link-active {
|
.resources.router-link-active, .namespace.router-link-active {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,9 +24,3 @@ defineProps<{
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
|
||||||
.grid-element {
|
|
||||||
height: 2.25rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<TableComponent :loading="configMaps == null">
|
<TableComponent :loading="configMaps == null" v-for="configMaps in [repo.get().value]">
|
||||||
<div class="resource-container config-map-container">
|
<div class="resource-container config-map-container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<p>Name</p>
|
<p>Name</p>
|
||||||
@ -14,10 +14,15 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ConfigMap } from '~/classes/ConfigMap';
|
import type { ConfigMap } from '~/classes/ConfigMap';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
|
|
||||||
const configMaps = ResourceRepo.init<ConfigMap>().load('config-maps').get();
|
|
||||||
|
|
||||||
|
const repo = ResourceRepo.init<ConfigMap>();
|
||||||
|
onMounted(() => {
|
||||||
|
repo.listen("config-maps");
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
repo.clear();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CustomResourceDefinition } from '~/classes/CustomResourceDefinition';
|
import type { CustomResourceDefinition } from '~/classes/CustomResourceDefinition';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
|
|
||||||
const customResourceDefinitions = ResourceRepo.init<CustomResourceDefinition>().load('custom-resource-definitions').get();
|
const customResourceDefinitions = ResourceRepo.init<CustomResourceDefinition>().load('custom-resource-definitions').get();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Deployment } from '~/classes/Deployment';
|
import type { Deployment } from '~/classes/Deployment';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
import DeploymentComponent from '~/components/deployments/DeploymentComponent.vue';
|
import DeploymentComponent from '~/components/deployments/DeploymentComponent.vue';
|
||||||
|
|
||||||
const deployments = ResourceRepo.init<Deployment>().load('deployments').get();
|
const deployments = ResourceRepo.init<Deployment>().load('deployments').get();
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Ingress } from '~/classes/Ingress';
|
import type { Ingress } from '~/classes/Ingress';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
|
|
||||||
const ingresses = ResourceRepo.init<Ingress>().load('ingresses').get();
|
const ingresses = ResourceRepo.init<Ingress>().load('ingresses').get();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Node } from '~/classes/Node';
|
import type { Node } from '~/classes/Node';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
import NodeComponent from '~/components/NodeComponent.vue';
|
import NodeComponent from '~/components/NodeComponent.vue';
|
||||||
|
|
||||||
const node = ResourceRepo.init<Node>().load('nodes').get();
|
const node = ResourceRepo.init<Node>().load('nodes').get();
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Pod } from '~/classes/Pod';
|
import type { Pod } from '~/classes/Pod';
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
import PodComponent from '~/components/pod/PodComponent.vue';
|
import PodComponent from '~/components/pod/PodComponent.vue';
|
||||||
|
|
||||||
const repo = ResourceRepo.init<Pod>();
|
const repo = ResourceRepo.init<Pod>();
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
import type { Secret } from '~/classes/Secret';
|
import type { Secret } from '~/classes/Secret';
|
||||||
import SecretComponent from '~/components/secrets/SecretComponent.vue';
|
import SecretComponent from '~/components/secrets/SecretComponent.vue';
|
||||||
import SecretAddComponent from '~/components/secrets/SecretAddComponent.vue';
|
import SecretAddComponent from '~/components/secrets/SecretAddComponent.vue';
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ResourceRepo } from '~/classes/ResourceRepo';
|
import { ResourceRepo } from '~/classes/repo/ResourceRepo';
|
||||||
import type { Service } from '~/classes/Service';
|
import type { Service } from '~/classes/Service';
|
||||||
|
|
||||||
const services = ResourceRepo.init<Service>().load('services').get();
|
const services = ResourceRepo.init<Service>().load('services').get();
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<div class="grid-element action-buttons">
|
<div class="grid-element action-buttons">
|
||||||
<ActionButton @click="showLogPopup = true">text_snippet</ActionButton>
|
<ActionButton @click="showLogPopup = true">text_snippet</ActionButton>
|
||||||
<ActionButton>open_in_full</ActionButton>
|
<ActionButton>open_in_full</ActionButton>
|
||||||
<ActionButton @click="showDeletePopup = true" v-if="hasAnyRole(getUser(), ['admin', 'maintainer'])">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>
|
<LogPopup v-if="showLogPopup" :pod="pod" @close="showLogPopup = false"></LogPopup>
|
||||||
@ -22,7 +22,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
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 PodDeletePopup from './view/PodDeletePopup.vue';
|
import PodDeletePopup from './view/PodDeletePopup.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|||||||
@ -1,13 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="account-page">
|
<div class="account-page">
|
||||||
<NuxtPage></NuxtPage>
|
|
||||||
<div class="left-center footer">
|
<div class="left-center footer">
|
||||||
|
<img class="logo" src="/assets/transparent_logo.png" alt="">
|
||||||
|
<div>
|
||||||
|
<h3>Kubooboo</h3>
|
||||||
|
<div class="left-center">
|
||||||
<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>
|
<p class="pointer" @click="logout()">Logout</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<NuxtPage></NuxtPage>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -22,10 +28,15 @@ function logout()
|
|||||||
.account-page {
|
.account-page {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr auto;
|
grid-template-rows: auto 1fr;
|
||||||
}
|
}
|
||||||
.footer {
|
.footer {
|
||||||
background-color: rgb(235, 235, 235);
|
background-color: var(--tile-color);
|
||||||
padding: 1rem;
|
padding: 0.5rem;
|
||||||
|
border-bottom: 1px solid #c0d1ff;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user