1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-26 23:21:41 +01:00

wip: k8s mode dynamic

This commit is contained in:
Amir Raminfar
2025-12-19 08:42:12 -08:00
parent 55aeb46262
commit b46124d352
10 changed files with 108 additions and 11 deletions

View File

@@ -53,6 +53,7 @@ declare module 'vue' {
'Ic:sharpKeyboardReturn': typeof import('~icons/ic/sharp-keyboard-return')['default']
IndeterminateBar: typeof import('./components/common/IndeterminateBar.vue')['default']
'Ion:ellipsisVertical': typeof import('~icons/ion/ellipsis-vertical')['default']
K8sMenu: typeof import('./components/K8sMenu.vue')['default']
KeyShortcut: typeof import('./components/common/KeyShortcut.vue')['default']
LabeledInput: typeof import('./components/common/LabeledInput.vue')['default']
Links: typeof import('./components/Links.vue')['default']

View File

@@ -0,0 +1,86 @@
<template>
<div class="mb-2 flex items-center">
<div class="flex-1">K8s Menu</div>
<div class="flex-none">
<div class="dropdown dropdown-end dropdown-hover">
<label tabindex="0" class="btn btn-square btn-ghost btn-sm">
<ph:dots-three-vertical-bold />
</label>
<ul
tabindex="0"
class="menu dropdown-content rounded-box bg-base-200 border-base-content/20 z-50 w-52 border p-1 shadow-sm"
>
<li>
<a class="text-sm capitalize" @click="collapseAll()">
<material-symbols-light:collapse-all class="w-4" />
{{ $t("label.collapse-all") }}
</a>
</li>
</ul>
</div>
</div>
</div>
<ul class="menu w-full p-0 text-[0.95rem]" ref="menu">
<li v-for="{ name, services } in stacks" :key="name">
<details open>
<summary class="text-base-content/80 font-light">
<ph:stack />
{{ name }}
<router-link
:to="{ name: '/stack/[name]', params: { name } }"
class="btn btn-square btn-outline btn-primary btn-xs"
active-class="btn-active"
:title="$t('tooltip.merge-services')"
>
<ph:arrows-merge />
</router-link>
</summary>
<ul>
<li v-for="service in services" :key="service.name">
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
<ph:stack-simple />
<div class="truncate">
{{ service.name }}
</div>
</router-link>
</li>
</ul>
</details>
</li>
<li v-if="servicesWithoutStacks.length > 0">
<details open>
<summary class="text-base-content/80 font-light">
<ph:circles-four />
{{ $t("label.services") }}
</summary>
<ul>
<li v-for="service in servicesWithoutStacks" :key="service.name">
<router-link :to="{ name: '/service/[name]', params: { name: service.name } }" active-class="menu-active">
<ph:stack-simple />
<div class="truncate">
{{ service.name }}
</div>
</router-link>
</li>
</ul>
</details>
</li>
</ul>
</template>
<script lang="ts" setup>
const store = useSwarmStore();
const { stacks, services } = storeToRefs(store);
const servicesWithoutStacks = computed(() => services.value.filter((service) => !service.stack));
const menu = useTemplateRef("menu");
const collapseAll = () => {
const details = menu.value?.querySelectorAll("details");
details?.forEach((detail) => (detail.open = false));
};
</script>

View File

@@ -1,15 +1,18 @@
<template>
<div v-if="ready" data-testid="side-menu" class="flex min-h-0 flex-col w-full">
<div v-if="ready" data-testid="side-menu" class="flex min-h-0 w-full flex-col">
<Carousel v-model="selectedCard" class="flex-1">
<CarouselItem :title="$t('label.k8s-menu')" v-if="config.mode === 'k8s'" id="k8s">
<K8sMenu />
</CarouselItem>
<CarouselItem :title="$t('label.swarm-menu')" v-if="config.mode === 'swarm' && services.length > 0" id="swarm">
<SwarmMenu />
</CarouselItem>
<CarouselItem :title="$t('label.host-menu')" id="host">
<HostMenu />
</CarouselItem>
<CarouselItem :title="$t('label.group-menu')" v-if="customGroups.length > 0" id="group">
<GroupMenu />
</CarouselItem>
<CarouselItem :title="$t('label.swarm-menu')" v-if="services.length > 0" id="swarm">
<SwarmMenu />
</CarouselItem>
</Carousel>
</div>
<div role="status" class="flex animate-pulse flex-col gap-4" v-else>
@@ -24,13 +27,13 @@ const { ready } = storeToRefs(containerStore);
const route = useRoute();
const swarmStore = useSwarmStore();
const { services, customGroups } = storeToRefs(swarmStore);
const selectedCard = ref<"host" | "swarm" | "group">("host");
const selectedCard = ref<"host" | "swarm" | "group" | "k8s">("host");
watch(
route,
() => {
if (route.meta.menu && ["host", "swarm", "group"].includes(route.meta.menu as string)) {
selectedCard.value = route.meta.menu as "host" | "swarm" | "group";
if (route.meta.menu && ["host", "swarm", "group", "k8s"].includes(route.meta.menu as string)) {
selectedCard.value = route.meta.menu as "host" | "swarm" | "group" | "k8s";
}
},
{ immediate: true },

View File

@@ -22,6 +22,7 @@ export interface Config {
name: string;
};
profile?: Profile;
mode: "swarm" | "k8s" | "server";
}
export interface Profile {

View File

@@ -50,7 +50,6 @@ spec:
containers:
- name: dozzle
image: amir20/dozzle:latest
imagePullPolicy: Never
ports:
- containerPort: 8080
env:

View File

@@ -96,7 +96,7 @@ func podToContainers(pod *corev1.Pod) []container.Container {
}
var containers []container.Container
for _, c := range pod.Spec.Containers {
containers = append(containers, container.Container{
container := container.Container{
ID: pod.Namespace + ":" + pod.Name + ":" + c.Name,
Name: pod.Name + "/" + c.Name,
Image: c.Image,
@@ -108,7 +108,11 @@ func podToContainers(pod *corev1.Pod) []container.Container {
Tty: c.TTY,
Stats: utils.NewRingBuffer[container.ContainerStat](300),
FullyLoaded: true,
})
}
if len(pod.OwnerReferences) > 0 {
container.Group = pod.OwnerReferences[0].Name
}
containers = append(containers, container)
}
return containers
}

View File

@@ -32,7 +32,7 @@ type Args struct {
RemoteHost []string `arg:"env:DOZZLE_REMOTE_HOST,--remote-host,separate" help:"list of hosts to connect remotely"`
RemoteAgent []string `arg:"env:DOZZLE_REMOTE_AGENT,--remote-agent,separate" help:"list of agents to connect remotely"`
NoAnalytics bool `arg:"--no-analytics,env:DOZZLE_NO_ANALYTICS" help:"disables anonymous analytics"`
Mode string `arg:"env:DOZZLE_MODE" default:"server" help:"sets the mode to run in (server, swarm)"`
Mode string `arg:"env:DOZZLE_MODE" default:"server" help:"sets the mode to run in (server, swarm, k8s)"`
TimeoutString string `arg:"--timeout,env:DOZZLE_TIMEOUT" default:"10s" help:"sets the timeout for docker client"`
Timeout time.Duration `arg:"-"`
Namespace []string `arg:"env:DOZZLE_NAMESPACE" help:"sets the namespace to use in k8s"`

View File

@@ -65,6 +65,7 @@ func (h *handler) executeTemplate(w http.ResponseWriter, req *http.Request) {
config["hosts"] = hosts
config["disableAvatars"] = h.config.DisableAvatars
config["releaseCheckMode"] = h.config.ReleaseCheckMode
config["mode"] = h.config.Mode
}
if user != nil {

View File

@@ -46,6 +46,7 @@ type Config struct {
DisableAvatars bool
ReleaseCheckMode ReleaseCheckMode
Labels container.ContainerLabels
Mode string
}
type Authorization struct {

View File

@@ -215,6 +215,7 @@ func createServer(args cli.Args, hostService web.HostService) *http.Server {
DisableAvatars: args.DisableAvatars,
ReleaseCheckMode: releaseCheckMode,
Labels: args.Filter,
Mode: args.Mode,
}
assets, err := fs.Sub(content, "dist")