Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
83 lines
2.4 KiB
Vue
83 lines
2.4 KiB
Vue
<template>
|
|
<PageWithLinks>
|
|
<section>
|
|
<div class="mb-4 flex items-center justify-between">
|
|
<h2 class="text-lg font-semibold">{{ $t("label.host-count", { count: Object.keys(hosts).length }) }}</h2>
|
|
<button @click="hostsCollapsed = !hostsCollapsed" class="icon-btn btn btn-ghost btn-sm">
|
|
<mdi:chevron-down :class="{ 'rotate-180': !hostsCollapsed }" class="transition-transform" />
|
|
</button>
|
|
</div>
|
|
<Transition name="collapse">
|
|
<HostList v-show="!hostsCollapsed" />
|
|
</Transition>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="mb-4 flex items-center justify-between">
|
|
<h2 class="text-lg font-semibold">
|
|
{{ $t("label.container", { count: dashboardContainers.length }) }}
|
|
</h2>
|
|
<button @click="containersCollapsed = !containersCollapsed" class="icon-btn btn btn-ghost btn-sm">
|
|
<mdi:chevron-down :class="{ 'rotate-180': !containersCollapsed }" class="transition-transform" />
|
|
</button>
|
|
</div>
|
|
<Transition name="collapse">
|
|
<ContainerTable v-show="!containersCollapsed" :containers="dashboardContainers" />
|
|
</Transition>
|
|
</section>
|
|
</PageWithLinks>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { Container } from "@/models/Container";
|
|
|
|
const { t } = useI18n();
|
|
const { hosts } = useHosts();
|
|
|
|
const containerStore = useContainerStore();
|
|
const { containers, ready } = storeToRefs(containerStore) as unknown as {
|
|
containers: Ref<Container[]>;
|
|
ready: Ref<boolean>;
|
|
};
|
|
|
|
const dashboardContainers = computed(() =>
|
|
containers.value.filter((c) => (showAllContainers.value ? c.state !== "deleted" : c.state === "running")),
|
|
);
|
|
|
|
const hostsCollapsed = useStorage("DOZZLE_HOSTS_COLLAPSED", false);
|
|
const containersCollapsed = useStorage("DOZZLE_CONTAINERS_COLLAPSED", false);
|
|
|
|
watchEffect(() => {
|
|
if (ready.value) {
|
|
setTitle(t("title.dashboard", { count: dashboardContainers.value.length }));
|
|
}
|
|
});
|
|
</script>
|
|
<style scoped>
|
|
:deep(tr td) {
|
|
padding-top: 1em;
|
|
padding-bottom: 1em;
|
|
}
|
|
|
|
.collapse-enter-active,
|
|
.collapse-leave-active {
|
|
transition:
|
|
opacity 200ms cubic-bezier(0.22, 1, 0.36, 1),
|
|
max-height 240ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.collapse-enter-from,
|
|
.collapse-leave-to {
|
|
opacity: 0;
|
|
max-height: 0;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.collapse-enter-active,
|
|
.collapse-leave-active {
|
|
transition: none;
|
|
}
|
|
}
|
|
</style>
|