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

feat: adds a new drop down to jump to same name containers (#3510)

This commit is contained in:
Amir Raminfar
2025-01-06 12:57:20 -08:00
committed by GitHub
parent 756b212826
commit 917c837e90
7 changed files with 132 additions and 17 deletions

View File

@@ -476,7 +476,6 @@ declare module 'vue' {
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']> readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onElementRemoval: UnwrapRef<typeof import('@vueuse/core')['onElementRemoval']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']> readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']>
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']> readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']>
@@ -671,7 +670,6 @@ declare module 'vue' {
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']>
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']>
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']> readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']>
readonly usePreferredReducedTransparency: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedTransparency']>
readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']> readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']>
readonly useProfileStorage: UnwrapRef<typeof import('./composable/profileStorage')['useProfileStorage']> readonly useProfileStorage: UnwrapRef<typeof import('./composable/profileStorage')['useProfileStorage']>
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
@@ -680,7 +678,6 @@ declare module 'vue' {
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']> readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']> readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']> readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']> readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']> readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>

View File

@@ -3,7 +3,11 @@
<template #header v-if="showTitle"> <template #header v-if="showTitle">
<div class="@container mx-2 flex items-center gap-2 md:ml-4"> <div class="@container mx-2 flex items-center gap-2 md:ml-4">
<ContainerTitle :container="container" /> <ContainerTitle :container="container" />
<MultiContainerStat class="ml-auto lg:hidden lg:@3xl:flex" :containers="[container]" /> <MultiContainerStat
class="ml-auto lg:hidden lg:@3xl:flex"
:containers="[container]"
v-if="container.state === 'running'"
/>
<ContainerActionsToolbar @clear="viewer?.clear()" class="mobile-hidden" :container="container" /> <ContainerActionsToolbar @clear="viewer?.clear()" class="mobile-hidden" :container="container" />
<a class="btn btn-circle btn-xs" @click="close()" v-if="closable"> <a class="btn btn-circle btn-xs" @click="close()" v-if="closable">

View File

@@ -1,20 +1,38 @@
<template> <template>
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2"> <div class="@container flex flex-1 items-center gap-1.5 truncate md:gap-2">
<label class="swap swap-rotate size-4"> <label class="swap swap-rotate size-4">
<input type="checkbox" v-model="pinned" /> <input type="checkbox" v-model="pinned" />
<carbon:star-filled class="swap-on text-secondary" /> <carbon:star-filled class="swap-on text-secondary" />
<carbon:star class="swap-off" /> <carbon:star class="swap-off" />
</label> </label>
<div class="inline-flex font-mono text-sm"> <div class="inline-flex items-center text-sm">
<div v-if="config.hosts.length > 1" class="mobile-hidden font-thin"> <div class="breadcrumbs p-0">
{{ container.hostLabel }}<span class="mx-2">/</span> <ul>
</div> <li v-if="config.hosts.length > 1" class="mobile-hidden font-thin">
<div class="font-semibold">{{ container.name }}</div> {{ container.hostLabel }}
</li>
<li>
<div class="wrapper" ref="wrapper">
<button popovertarget="popover-container-list" class="btn btn-xs md:btn-sm anchor font-mono">
{{ container.name }} <carbon:caret-down />
</button>
<ul popover id="popover-container-list" class="dropdown menu rounded-box bg-base-100 tethered shadow-sm">
<li v-for="other in otherContainers">
<router-link :to="{ name: '/container/[id]', params: { id: other.id } }">
<div <div
class="mobile-hidden max-w-[1.5em] truncate transition-[max-width] hover:max-w-[400px]" class="status data-[state=exited]:status-error data-[state=running]:status-success"
v-if="container.isSwarm" :data-state="other.state"
> ></div>
.{{ container.swarmId }} <div class="font-mono" v-if="other.isSwarm">{{ other.swarmId }}</div>
<div class="font-mono" v-else>{{ other.name }}</div>
<div v-if="other.state === 'running'">running</div>
<DistanceTime :date="other.created" strict class="text-base-content/70 text-xs" v-else />
</router-link>
</li>
</ul>
</div>
</li>
</ul>
</div> </div>
</div> </div>
<ContainerHealth :health="container.health" v-if="container.health" /> <ContainerHealth :health="container.health" v-if="container.health" />
@@ -38,4 +56,41 @@ const pinned = computed({
} }
}, },
}); });
const store = useContainerStore();
const { containers: allContainers } = storeToRefs(store);
const otherContainers = computed(() =>
[...allContainers.value.filter((c) => c.name === container.name && c.id !== container.id)].sort(
(a, b) => +b.created - +a.created,
),
);
const wrapper = useTemplateRef("wrapper");
onMounted(async () => {
if (!("anchorName" in document.documentElement.style)) {
// @ts-ignore
const module = await import("@oddbird/css-anchor-positioning/fn");
// @ts-ignore
await module.default([wrapper.value]);
}
});
</script> </script>
<style scoped>
/* https://github.com/oddbird/css-anchor-positioning/issues/282 */
.wrapper {
anchor-scope: --anchor;
}
.anchor {
anchor-name: --anchor;
}
.tethered {
margin: 0;
padding: 0;
position-anchor: --anchor;
top: anchor(bottom);
left: anchor(left);
}
</style>

View File

@@ -83,7 +83,7 @@
class="group auto-cols-[auto_max-content_max-content]" class="group auto-cols-[auto_max-content_max-content]"
> >
<div class="truncate"> <div class="truncate">
{{ item.name }}<span class="font-light opacity-70" v-if="item.isSwarm">.{{ item.swarmId }}</span> {{ item.name }}
</div> </div>
<ContainerHealth :health="item.health" /> <ContainerHealth :health="item.health" />
<span <span

View File

@@ -6,5 +6,4 @@ const app = createApp(App);
Object.values(import.meta.glob<{ install: (app: VueApp) => void }>("./modules/*.ts", { eager: true })).forEach((i) => Object.values(import.meta.glob<{ install: (app: VueApp) => void }>("./modules/*.ts", { eager: true })).forEach((i) =>
i.install?.(app), i.install?.(app),
); );
app.mount("#app"); app.mount("#app");

View File

@@ -39,6 +39,7 @@
"@iconify-json/octicon": "^1.2.2", "@iconify-json/octicon": "^1.2.2",
"@iconify-json/ph": "^1.2.2", "@iconify-json/ph": "^1.2.2",
"@intlify/unplugin-vue-i18n": "^6.0.3", "@intlify/unplugin-vue-i18n": "^6.0.3",
"@oddbird/css-anchor-positioning": "^0.4.0",
"@tailwindcss/typography": "^0.5.15", "@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "4.0.0-beta.8", "@tailwindcss/vite": "4.0.0-beta.8",
"@vueuse/components": "^12.3.0", "@vueuse/components": "^12.3.0",

59
pnpm-lock.yaml generated
View File

@@ -38,6 +38,9 @@ importers:
'@intlify/unplugin-vue-i18n': '@intlify/unplugin-vue-i18n':
specifier: ^6.0.3 specifier: ^6.0.3
version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.10.0(jiti@2.4.1))(rollup@4.28.1)(typescript@5.7.2)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2)) version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.10.0(jiti@2.4.1))(rollup@4.28.1)(typescript@5.7.2)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))
'@oddbird/css-anchor-positioning':
specifier: ^0.4.0
version: 0.4.0
'@tailwindcss/typography': '@tailwindcss/typography':
specifier: ^0.5.15 specifier: ^0.5.15
version: 0.5.15(tailwindcss@4.0.0-beta.8) version: 0.5.15(tailwindcss@4.0.0-beta.8)
@@ -863,6 +866,15 @@ packages:
resolution: {integrity: sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==} resolution: {integrity: sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@floating-ui/core@1.6.8':
resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==}
'@floating-ui/dom@1.6.12':
resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==}
'@floating-ui/utils@0.2.8':
resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==}
'@humanwhocodes/module-importer@1.0.1': '@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'} engines: {node: '>=12.22'}
@@ -1003,6 +1015,9 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@oddbird/css-anchor-positioning@0.4.0':
resolution: {integrity: sha512-K3iVeBnuXIaDj4/rrFxPJBPEgghBsofL/64hiegkqkyPBk79c0h6r6gSlNCXrtf1b0cWiC55BV6PC1Y0Ph/1NQ==}
'@one-ini/wasm@0.1.1': '@one-ini/wasm@0.1.1':
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
@@ -1413,6 +1428,9 @@ packages:
'@types/command-line-usage@5.0.4': '@types/command-line-usage@5.0.4':
resolution: {integrity: sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==} resolution: {integrity: sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==}
'@types/css-tree@2.3.10':
resolution: {integrity: sha512-WcaBazJ84RxABvRttQjjFWgTcHvZR9jGr0Y3hccPkHjFyk/a3N8EuxjKr+QfrwjoM5b1yI1Uj1i7EzOAAwBwag==}
'@types/d3-array@3.2.1': '@types/d3-array@3.2.1':
resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==}
@@ -2205,6 +2223,10 @@ packages:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
css-tree@3.1.0:
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
css-what@6.1.0: css-what@6.1.0:
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -2990,6 +3012,9 @@ packages:
mdn-data@2.0.30: mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
mdn-data@2.12.2:
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
merge-stream@2.0.0: merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -3092,6 +3117,11 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
nanoid@5.0.9:
resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==}
engines: {node: ^18 || >=20}
hasBin: true
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@@ -4565,6 +4595,17 @@ snapshots:
dependencies: dependencies:
levn: 0.4.1 levn: 0.4.1
'@floating-ui/core@1.6.8':
dependencies:
'@floating-ui/utils': 0.2.8
'@floating-ui/dom@1.6.12':
dependencies:
'@floating-ui/core': 1.6.8
'@floating-ui/utils': 0.2.8
'@floating-ui/utils@0.2.8': {}
'@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/module-importer@1.0.1': {}
'@humanwhocodes/retry@0.3.1': {} '@humanwhocodes/retry@0.3.1': {}
@@ -4733,6 +4774,13 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1 fastq: 1.17.1
'@oddbird/css-anchor-positioning@0.4.0':
dependencies:
'@floating-ui/dom': 1.6.12
'@types/css-tree': 2.3.10
css-tree: 3.1.0
nanoid: 5.0.9
'@one-ini/wasm@0.1.1': {} '@one-ini/wasm@0.1.1': {}
'@oxc-resolver/binding-darwin-arm64@2.1.1': '@oxc-resolver/binding-darwin-arm64@2.1.1':
@@ -5041,6 +5089,8 @@ snapshots:
'@types/command-line-usage@5.0.4': {} '@types/command-line-usage@5.0.4': {}
'@types/css-tree@2.3.10': {}
'@types/d3-array@3.2.1': {} '@types/d3-array@3.2.1': {}
'@types/d3-ease@3.0.2': {} '@types/d3-ease@3.0.2': {}
@@ -6015,6 +6065,11 @@ snapshots:
mdn-data: 2.0.30 mdn-data: 2.0.30
source-map-js: 1.2.1 source-map-js: 1.2.1
css-tree@3.1.0:
dependencies:
mdn-data: 2.12.2
source-map-js: 1.2.1
css-what@6.1.0: {} css-what@6.1.0: {}
cssesc@3.0.0: {} cssesc@3.0.0: {}
@@ -6854,6 +6909,8 @@ snapshots:
mdn-data@2.0.30: {} mdn-data@2.0.30: {}
mdn-data@2.12.2: {}
merge-stream@2.0.0: {} merge-stream@2.0.0: {}
merge2@1.4.1: {} merge2@1.4.1: {}
@@ -6938,6 +6995,8 @@ snapshots:
nanoid@3.3.7: {} nanoid@3.3.7: {}
nanoid@5.0.9: {}
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
node-fetch-native@1.6.4: {} node-fetch-native@1.6.4: {}