feat: Command palette in Cmd+K search (#4861)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Amir Raminfar
2026-07-25 10:45:26 -07:00
committed by GitHub
parent df5a60479c
commit f348b57721
20 changed files with 624 additions and 57 deletions
+5
View File
@@ -219,6 +219,7 @@ declare global {
const useCloudConfig: typeof import('./composable/cloudConfig').useCloudConfig
const useCloudLogSearch: typeof import('./composable/cloudLogSearch').useCloudLogSearch
const useColorMode: typeof import('@vueuse/core').useColorMode
const useCommands: typeof import('./composable/commands').useCommands
const useConfirmDialog: typeof import('@vueuse/core').useConfirmDialog
const useContainerActions: typeof import('./composable/containerActions').useContainerActions
const useContainerStore: typeof import('./stores/container').useContainerStore
@@ -423,6 +424,9 @@ declare global {
export type { CloudLogHit } from './composable/cloudLogSearch'
import('./composable/cloudLogSearch')
// @ts-ignore
export type { CommandSection, Command } from './composable/commands'
import('./composable/commands')
// @ts-ignore
export type { DrawerWidth } from './composable/drawer'
import('./composable/drawer')
// @ts-ignore
@@ -661,6 +665,7 @@ declare module 'vue' {
readonly useCloudConfig: UnwrapRef<typeof import('./composable/cloudConfig')['useCloudConfig']>
readonly useCloudLogSearch: UnwrapRef<typeof import('./composable/cloudLogSearch')['useCloudLogSearch']>
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
readonly useCommands: UnwrapRef<typeof import('./composable/commands')['useCommands']>
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
readonly useContainerActions: UnwrapRef<typeof import('./composable/containerActions')['useContainerActions']>
readonly useContainerStore: UnwrapRef<typeof import('./stores/container')['useContainerStore']>
+26 -1
View File
@@ -4,6 +4,7 @@ import { mount } from "@vue/test-utils";
import FuzzySearchModal from "./FuzzySearchModal.vue";
import { Container } from "@/models/Container";
import { lightTheme } from "@/stores/settings";
import { beforeEach, describe, expect, test, vi } from "vitest";
import { createI18n } from "vue-i18n";
import { useRouter } from "vue-router";
@@ -16,7 +17,7 @@ vi.mock("vue-router");
vi.mock("@/stores/config", () => ({
__esModule: true,
default: { base: "", hosts: [{ name: "localhost", id: "localhost" }] },
default: { base: "", hosts: [{ name: "localhost", id: "localhost" }], enableActions: true },
withBase: (path: string) => path,
}));
@@ -119,4 +120,28 @@ describe("<FuzzySearchModal />", () => {
await wrapper.find("input").trigger("keydown.enter");
expect(useRouter().push).toHaveBeenCalledWith({ name: "/container/[id]", params: { id: "567" } });
});
test("matches commands by keyword", async () => {
const wrapper = createFuzzySearchModal();
await wrapper.find("input").setValue("theme");
const items = wrapper.findAll("li").map((li) => li.text());
expect(items).toContain("command-palette.theme-dark");
});
test("theme commands set the theme explicitly", async () => {
lightTheme.value = "auto";
const wrapper = createFuzzySearchModal();
await wrapper.find("input").setValue("dark theme");
await wrapper.find("input").trigger("keydown.enter");
expect(lightTheme.value).toBe("dark");
await wrapper.find("input").setValue("light theme");
await wrapper.find("input").trigger("keydown.enter");
expect(lightTheme.value).toBe("light");
await wrapper.find("input").setValue("system theme");
await wrapper.find("input").trigger("keydown.enter");
expect(lightTheme.value).toBe("auto");
});
});
+136 -56
View File
@@ -9,11 +9,11 @@
tabindex="0"
class="text-base-content placeholder:text-base-content/40 flex-1 bg-transparent text-base outline-none"
ref="input"
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, data.length - 1)"
@keydown.down="selectedIndex = Math.min(selectedIndex + 1, totalCount - 1)"
@keydown.up="selectedIndex = Math.max(selectedIndex - 1, 0)"
@keydown.enter.exact="onEnter"
@keydown.shift.enter.exact.prevent="runLogSearch"
@keydown.alt.enter="addColumn(data[selectedIndex].item)"
@keydown.alt.enter.exact.prevent="onPin"
v-model="query"
:placeholder="placeholderCopy"
/>
@@ -29,51 +29,80 @@
<!-- Body: results + log search CTA. Only renders when there is something
to show keeps the empty modal compact. -->
<div v-if="results.length || logSearchVisible" class="border-base-content/10 border-t">
<!-- Containers section -->
<template v-if="results.length">
<div class="text-base-content/40 px-4 pt-3 pb-1.5 text-xs font-semibold tracking-wider uppercase">
{{ $t("cloud-search.containers-section") }} · {{ data.length }}
</div>
<ul class="max-h-[50vh] overflow-y-auto overscroll-contain pb-1">
<li v-for="(result, index) in data" ref="listItems">
<a
class="hover:bg-base-content/5 flex cursor-pointer items-center gap-3 px-4 py-2"
:class="{ 'bg-base-content/10': index === selectedIndex }"
@click.prevent="selected(result.item)"
>
<div :class="result.item.state === 'running' ? 'text-primary' : 'text-base-content/50'">
<template v-if="result.item.type === 'container'">
<octicon:container-24 class="size-4" />
</template>
<template v-else-if="result.item.type === 'service'">
<ph:stack-simple class="size-4" />
</template>
<template v-else-if="result.item.type === 'stack'">
<ph:stack class="size-4" />
</template>
</div>
<div class="min-w-0 flex-1 truncate text-sm">
<template v-if="config.hosts.length > 1 && result.item.host">
<span class="text-base-content/50 font-light">{{ result.item.host }}</span>
<span class="text-base-content/30"> / </span>
</template>
<span class="text-base-content" data-name v-html="matchedName(result)"></span>
</div>
<RelativeTime :date="result.item.created" class="text-base-content/40 text-xs" />
<span
@click.stop.prevent="addColumn(result.item)"
:title="$t('tooltip.pin-column')"
class="text-base-content/40 hover:text-secondary"
<div v-if="totalCount || logSearchVisible" class="border-base-content/10 border-t">
<!-- Scroll container spans both sections so the flat Commands + Containers
list scrolls as one, matching the unified selection index. -->
<div class="max-h-[50vh] overflow-y-auto overscroll-contain">
<!-- Commands section -->
<template v-if="commandEntries.length">
<div class="text-base-content/40 px-4 pt-3 pb-1.5 text-xs font-semibold tracking-wider uppercase">
{{ $t("command-palette.section-commands") }} · {{ commandEntries.length }}
</div>
<ul class="pb-1">
<li v-for="(command, index) in commandEntries" :ref="(el) => setItemRef(el, index)">
<a
class="hover:bg-base-content/5 flex cursor-pointer items-center gap-3 px-4 py-2"
:class="{ 'bg-base-content/10': index === selectedIndex }"
@click.prevent="runCommand(command)"
>
<ic:sharp-keyboard-return v-if="index === selectedIndex" class="size-4" />
<cil:columns v-else-if="result.item.type === 'container'" class="size-4" />
</span>
</a>
</li>
</ul>
</template>
<component :is="command.icon" class="text-base-content/60 size-4 shrink-0" />
<span class="min-w-0 flex-1 truncate text-sm">{{ command.title }}</span>
<ic:sharp-keyboard-return v-if="index === selectedIndex" class="text-base-content/40 size-4" />
</a>
</li>
</ul>
</template>
<!-- Containers section -->
<template v-if="containerEntries.length">
<div
class="text-base-content/40 px-4 pt-3 pb-1.5 text-xs font-semibold tracking-wider uppercase"
:class="{ 'border-base-content/10 mt-1 border-t': commandEntries.length }"
>
{{ $t("cloud-search.containers-section") }} · {{ containerEntries.length }}
</div>
<ul class="pb-1">
<li
v-for="(result, index) in containerEntries"
:ref="(el) => setItemRef(el, commandEntries.length + index)"
>
<a
class="hover:bg-base-content/5 flex cursor-pointer items-center gap-3 px-4 py-2"
:class="{ 'bg-base-content/10': commandEntries.length + index === selectedIndex }"
@click.prevent="selected(result.item)"
>
<div :class="result.item.state === 'running' ? 'text-primary' : 'text-base-content/50'">
<template v-if="result.item.type === 'container'">
<octicon:container-24 class="size-4" />
</template>
<template v-else-if="result.item.type === 'service'">
<ph:stack-simple class="size-4" />
</template>
<template v-else-if="result.item.type === 'stack'">
<ph:stack class="size-4" />
</template>
</div>
<div class="min-w-0 flex-1 truncate text-sm">
<template v-if="config.hosts.length > 1 && result.item.host">
<span class="text-base-content/50 font-light">{{ result.item.host }}</span>
<span class="text-base-content/30"> / </span>
</template>
<span class="text-base-content" data-name v-html="matchedName(result)"></span>
</div>
<RelativeTime :date="result.item.created" class="text-base-content/40 text-xs" />
<span
@click.stop.prevent="addColumn(result.item)"
:title="$t('tooltip.pin-column')"
class="text-base-content/40 hover:text-secondary"
>
<ic:sharp-keyboard-return v-if="commandEntries.length + index === selectedIndex" class="size-4" />
<cil:columns v-else-if="result.item.type === 'container'" class="size-4" />
</span>
</a>
</li>
</ul>
</template>
</div>
<!-- Log search CTA -->
<div
v-if="logSearchVisible"
@@ -130,7 +159,7 @@
<div
class="bg-base-300/40 border-base-content/10 text-base-content/50 flex items-center gap-4 border-t px-4 py-2 text-xs"
>
<span v-if="results.length" class="flex items-center gap-1.5">
<span v-if="totalCount" class="flex items-center gap-1.5">
<kbd class="kbd kbd-xs"></kbd> {{ $t("cloud-search.open-container") }}
</span>
<span v-if="cloudSearch.available.value && logSearchVisible" class="flex items-center gap-1">
@@ -164,6 +193,7 @@ import { useFuse } from "@vueuse/integrations/useFuse";
import { type FuseResult } from "fuse.js";
import { useCloudConfig } from "@/composable/cloudConfig";
import { useCloudLogSearch } from "@/composable/cloudLogSearch";
import { useCommands, type Command } from "@/composable/commands";
const close = defineEmit();
@@ -176,9 +206,15 @@ const route = useRoute();
const initialQuery = route?.path === "/cloud/search" && typeof route.query?.q === "string" ? route.query.q : "";
const query = ref(initialQuery);
const input = ref<HTMLInputElement>();
const listItems = ref<HTMLInputElement[]>();
const listItems = ref<(Element | null)[]>([]);
const selectedIndex = ref(0);
// Function ref into a single flat array so Commands and Containers share one
// selection index for arrow-key navigation and scroll-into-view.
function setItemRef(el: any, index: number) {
listItems.value[index] = (el?.$el ?? el) as Element | null;
}
const containerStore = useContainerStore();
const pinnedStore = usePinnedLogsStore();
const { visibleContainers } = storeToRefs(containerStore);
@@ -268,6 +304,20 @@ const { results: fuseResults } = useFuse(query, list, {
const results = computed(() => (query.value ? fuseResults.value : []));
// Commands palette. Fuzzy-matched against title/keywords while typing; the
// context commands (container actions) show up front on an empty query.
const { commands, contextCommands } = useCommands();
const { results: commandFuseResults } = useFuse(query, commands, {
fuseOptions: {
keys: ["title", "keywords"],
useExtendedSearch: true,
threshold: 0.3,
},
});
const commandEntries = computed<Command[]>(() =>
query.value ? commandFuseResults.value.map((r) => r.item) : contextCommands.value,
);
const data = computed(() => {
return [...results.value].sort((a: FuseResult<Item>, b: FuseResult<Item>) => {
if (a.score === b.score) {
@@ -284,14 +334,26 @@ const data = computed(() => {
});
});
watch(query, (data) => {
if (data.length > 0) {
selectedIndex.value = 0;
// Container hits, mirrors the previously named `data` list for the template.
const containerEntries = computed(() => data.value);
const totalCount = computed(() => commandEntries.value.length + containerEntries.value.length);
// Reset to the top only when the user types. Live SSE container add/remove
// changes totalCount too, and resetting on that would snap the selection back
// to 0 while the palette is open.
watch(query, () => {
selectedIndex.value = 0;
});
// Keep the selection in bounds when the result count shrinks underneath it.
watch(totalCount, (count) => {
if (selectedIndex.value > count - 1) {
selectedIndex.value = Math.max(count - 1, 0);
}
});
watch(selectedIndex, () => {
listItems.value?.[selectedIndex.value].scrollIntoView({ block: "end" });
listItems.value?.[selectedIndex.value]?.scrollIntoView({ block: "nearest" });
});
function selected(item: Item) {
@@ -305,17 +367,35 @@ function selected(item: Item) {
close();
}
async function runCommand(command: Command) {
close();
await command.perform();
}
function onEnter() {
// Plain Enter prefers a container match if one is selected. With no
// container matches (cloud-only query like "OOM"), fall back to log search
// so the user isn't stuck on a popup that does nothing.
if (data.value.length > 0) {
selected(data.value[selectedIndex.value].item);
// Commands come first in the flat list, then containers. With nothing
// selectable (cloud-only query like "OOM"), fall back to log search so the
// user isn't stuck on a popup that does nothing.
const commandCount = commandEntries.value.length;
if (selectedIndex.value < commandCount) {
runCommand(commandEntries.value[selectedIndex.value]);
} else if (containerEntries.value.length > 0) {
selected(containerEntries.value[selectedIndex.value - commandCount].item);
} else if (cloudSearch.available.value && logSearchVisible.value) {
runLogSearch();
}
}
function onPin() {
// Alt+Enter pins a container column. Only meaningful when a container row is
// selected, not a command.
const commandCount = commandEntries.value.length;
if (selectedIndex.value >= commandCount) {
const entry = containerEntries.value[selectedIndex.value - commandCount];
if (entry?.item.type === "container") addColumn(entry.item);
}
}
function runLogSearch() {
if (!cloudSearch.available.value) return;
const q = query.value.trim();
+201
View File
@@ -0,0 +1,201 @@
import type { Component } from "vue";
import { Container } from "@/models/Container";
import { useContainerActions } from "@/composable/containerActions";
import config from "@/stores/config";
import {
lightTheme,
compact,
showTimestamp,
softWrap,
showAllContainers,
showStd,
smallerScrollbars,
} from "@/stores/settings";
import mdiThemeLightDark from "~icons/mdi/theme-light-dark";
import mdiWhiteBalanceSunny from "~icons/mdi/white-balance-sunny";
import mdiWeatherNight from "~icons/mdi/weather-night";
import mdiFormatLineSpacing from "~icons/mdi/format-line-spacing";
import mdiClockOutline from "~icons/mdi/clock-outline";
import mdiWrap from "~icons/mdi/wrap";
import mdiEyeOutline from "~icons/mdi/eye-outline";
import mdiFormatListBulleted from "~icons/mdi/format-list-bulleted";
import mdiUnfoldMoreHorizontal from "~icons/mdi/unfold-more-horizontal";
import mdiCogOutline from "~icons/mdi/cog-outline";
import carbonRestart from "~icons/carbon/restart";
import mdiStop from "~icons/mdi/stop";
import mdiPlay from "~icons/mdi/play";
import mdiDownload from "~icons/mdi/download";
export type CommandSection = "container" | "settings" | "navigation";
export type Command = {
id: string;
title: string;
section: CommandSection;
icon: Component;
keywords?: string;
perform: () => unknown;
};
// Central registry for the Cmd+K command palette. Commands are recomputed on
// every access so context-sensitive entries (container actions, current
// toggle labels) stay in sync with the route and settings.
export function useCommands() {
const { t } = useI18n();
const router = useRouter();
const route = useRoute();
const containerStore = useContainerStore();
const currentId = computed(() =>
route?.name === "/container/[id]" && typeof route.params.id === "string" ? route.params.id : "",
);
// Null-safe: containerStore.currentContainer is a stubbed action under
// @pinia/testing, so guard against it being absent.
const currentContainerRef = containerStore.currentContainer?.(currentId);
const currentContainer = computed(() => currentContainerRef?.value as Container | undefined);
// Bound to the current container. The cast is safe because the action
// handlers only read container.value when invoked, and container commands are
// only pushed into the list when currentContainer is truthy — so the handlers
// never run against an undefined container.
const { start, stop, restart, update } = useContainerActions(currentContainer as Ref<Container>);
const commands = computed<Command[]>(() => {
const list: Command[] = [];
const container = currentContainer.value;
if (container && config.enableActions) {
const name = container.name;
list.push({
id: "container.restart",
section: "container",
icon: carbonRestart,
title: t("command-palette.restart-container", { name }),
keywords: "restart reboot",
perform: restart,
});
if (container.state === "running") {
list.push({
id: "container.stop",
section: "container",
icon: mdiStop,
title: t("command-palette.stop-container", { name }),
keywords: "stop kill halt",
perform: stop,
});
} else {
list.push({
id: "container.start",
section: "container",
icon: mdiPlay,
title: t("command-palette.start-container", { name }),
keywords: "start run",
perform: start,
});
}
list.push({
id: "container.update",
section: "container",
icon: mdiDownload,
title: t("command-palette.update-container", { name }),
keywords: "update pull recreate upgrade",
perform: update,
});
}
list.push(
// lightTheme is tri-state, so expose each value as its own command rather
// than a single toggle — that keeps "auto" (follow OS) reachable and makes
// the target theme explicit instead of depending on the current state.
{
id: "settings.theme-auto",
section: "settings",
icon: mdiThemeLightDark,
title: t("command-palette.theme-auto"),
keywords: "theme auto system color mode appearance",
perform: () => (lightTheme.value = "auto"),
},
{
id: "settings.theme-light",
section: "settings",
icon: mdiWhiteBalanceSunny,
title: t("command-palette.theme-light"),
keywords: "theme light color mode appearance",
perform: () => (lightTheme.value = "light"),
},
{
id: "settings.theme-dark",
section: "settings",
icon: mdiWeatherNight,
title: t("command-palette.theme-dark"),
keywords: "theme dark color mode appearance",
perform: () => (lightTheme.value = "dark"),
},
{
id: "settings.toggle-compact",
section: "settings",
icon: mdiFormatLineSpacing,
title: t("command-palette.toggle-compact"),
keywords: "compact density spacing",
perform: () => (compact.value = !compact.value),
},
{
id: "settings.toggle-timestamps",
section: "settings",
icon: mdiClockOutline,
title: t("command-palette.toggle-timestamps"),
keywords: "timestamp time date",
perform: () => (showTimestamp.value = !showTimestamp.value),
},
{
id: "settings.toggle-soft-wrap",
section: "settings",
icon: mdiWrap,
title: t("command-palette.toggle-soft-wrap"),
keywords: "wrap soft line",
perform: () => (softWrap.value = !softWrap.value),
},
{
id: "settings.toggle-stopped",
section: "settings",
icon: mdiEyeOutline,
title: t("command-palette.toggle-stopped"),
keywords: "stopped hidden all containers exited",
perform: () => (showAllContainers.value = !showAllContainers.value),
},
{
id: "settings.toggle-std",
section: "settings",
icon: mdiFormatListBulleted,
title: t("command-palette.toggle-std"),
keywords: "stdout stderr std labels stream",
perform: () => (showStd.value = !showStd.value),
},
{
id: "settings.toggle-scrollbars",
section: "settings",
icon: mdiUnfoldMoreHorizontal,
title: t("command-palette.toggle-scrollbars"),
keywords: "scrollbar smaller thin",
perform: () => (smallerScrollbars.value = !smallerScrollbars.value),
},
{
id: "navigation.settings",
section: "navigation",
icon: mdiCogOutline,
title: t("command-palette.open-settings"),
keywords: "settings preferences options config",
perform: () => router.push("/settings"),
},
);
return list;
});
// Commands shown before the user types anything: the context-sensitive
// container actions so e.g. Restart is one keystroke away on a container page.
const contextCommands = computed(() => commands.value.filter((c) => c.section === "container"));
return { commands, contextCommands };
}
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "Containeren er slettet"
cta-settings: "Cloud-indstillinger"
container-removed-pill: "slettet"
command-palette:
section-commands: Kommandoer
restart-container: Genstart {name}
stop-container: Stop {name}
start-container: Start {name}
update-container: Opdater {name}
theme-auto: Brug systemtema
theme-light: Skift til lyst tema
theme-dark: Skift til mørkt tema
toggle-compact: Skift kompakt tilstand
toggle-timestamps: Skift tidsstempler
toggle-soft-wrap: Skift blød ombrydning
toggle-stopped: Skift stoppede containere
toggle-std: Skift stdout/stderr-etiketter
toggle-scrollbars: Skift mindre rullepaneler
open-settings: Åbn indstillinger
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "Container wurde gelöscht"
cta-settings: "Cloud-Einstellungen"
container-removed-pill: "gelöscht"
command-palette:
section-commands: Befehle
restart-container: "{name} neu starten"
stop-container: "{name} stoppen"
start-container: "{name} starten"
update-container: "{name} aktualisieren"
theme-auto: Systemdesign verwenden
theme-light: Zu hellem Design wechseln
theme-dark: Zu dunklem Design wechseln
toggle-compact: Kompaktmodus umschalten
toggle-timestamps: Zeitstempel umschalten
toggle-soft-wrap: Zeilenumbruch umschalten
toggle-stopped: Gestoppte Container umschalten
toggle-std: stdout/stderr-Labels umschalten
toggle-scrollbars: Kleinere Scrollleisten umschalten
open-settings: Einstellungen öffnen
+16
View File
@@ -160,6 +160,22 @@ cloud-search:
container-removed: Container has been deleted
cta-settings: "Cloud settings"
container-removed-pill: removed
command-palette:
section-commands: Commands
restart-container: Restart {name}
stop-container: Stop {name}
start-container: Start {name}
update-container: Update {name}
theme-auto: Use system theme
theme-light: Switch to light theme
theme-dark: Switch to dark theme
toggle-compact: Toggle compact mode
toggle-timestamps: Toggle timestamps
toggle-soft-wrap: Toggle soft wrap
toggle-stopped: Toggle stopped containers
toggle-std: Toggle stdout/stderr labels
toggle-scrollbars: Toggle smaller scrollbars
open-settings: Open settings
settings:
help-support: >
Please support Dozzle by donating or sponsoring us on GitHub. Your contributions help us improve Dozzle for
+16
View File
@@ -156,6 +156,22 @@ cloud-search:
container-removed: "El contenedor ha sido eliminado"
cta-settings: "Configuración de Cloud"
container-removed-pill: "eliminado"
command-palette:
section-commands: Comandos
restart-container: Reiniciar {name}
stop-container: Detener {name}
start-container: Iniciar {name}
update-container: Actualizar {name}
theme-auto: Usar tema del sistema
theme-light: Cambiar a tema claro
theme-dark: Cambiar a tema oscuro
toggle-compact: Alternar modo compacto
toggle-timestamps: Alternar marcas de tiempo
toggle-soft-wrap: Alternar ajuste de línea
toggle-stopped: Alternar contenedores detenidos
toggle-std: Alternar etiquetas stdout/stderr
toggle-scrollbars: Alternar barras de desplazamiento más pequeñas
open-settings: Abrir configuración
settings:
help-support: >
Por favor, apoya a Dozzle donando o patrocinándonos en GitHub. Tus contribuciones nos ayudan a mejorar Dozzle para todos. ¡Gracias! 🙏🏼
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "Le conteneur a été supprimé"
cta-settings: "Paramètres Cloud"
container-removed-pill: "supprimé"
command-palette:
section-commands: Commandes
restart-container: Redémarrer {name}
stop-container: Arrêter {name}
start-container: Démarrer {name}
update-container: Mettre à jour {name}
theme-auto: Utiliser le thème du système
theme-light: Passer au thème clair
theme-dark: Passer au thème sombre
toggle-compact: Basculer le mode compact
toggle-timestamps: Basculer les horodatages
toggle-soft-wrap: Basculer le retour à la ligne
toggle-stopped: Basculer les conteneurs arrêtés
toggle-std: Basculer les étiquettes stdout/stderr
toggle-scrollbars: Basculer les barres de défilement réduites
open-settings: Ouvrir les paramètres
+16
View File
@@ -420,3 +420,19 @@ cloud-search:
container-removed: "Kontainer telah dihapus"
cta-settings: "Pengaturan Cloud"
container-removed-pill: "dihapus"
command-palette:
section-commands: Perintah
restart-container: Mulai ulang {name}
stop-container: Hentikan {name}
start-container: Jalankan {name}
update-container: Perbarui {name}
theme-auto: Gunakan tema sistem
theme-light: Beralih ke tema terang
theme-dark: Beralih ke tema gelap
toggle-compact: Alihkan mode ringkas
toggle-timestamps: Alihkan stempel waktu
toggle-soft-wrap: Alihkan bungkus lembut
toggle-stopped: Alihkan kontainer yang dihentikan
toggle-std: Alihkan label stdout/stderr
toggle-scrollbars: Alihkan bilah gulir lebih kecil
open-settings: Buka pengaturan
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "Il container è stato eliminato"
cta-settings: "Impostazioni Cloud"
container-removed-pill: "eliminato"
command-palette:
section-commands: Comandi
restart-container: Riavvia {name}
stop-container: Ferma {name}
start-container: Avvia {name}
update-container: Aggiorna {name}
theme-auto: Usa tema di sistema
theme-light: Passa al tema chiaro
theme-dark: Passa al tema scuro
toggle-compact: Attiva/disattiva modalità compatta
toggle-timestamps: Attiva/disattiva timestamp
toggle-soft-wrap: Attiva/disattiva a capo automatico
toggle-stopped: Attiva/disattiva container fermati
toggle-std: Attiva/disattiva etichette stdout/stderr
toggle-scrollbars: Attiva/disattiva barre di scorrimento più piccole
open-settings: Apri impostazioni
+16
View File
@@ -412,3 +412,19 @@ cloud-search:
container-removed: "컨테이너가 삭제되었습니다"
cta-settings: "Cloud 설정"
container-removed-pill: "삭제됨"
command-palette:
section-commands: 명령
restart-container: "{name} 재시작"
stop-container: "{name} 중지"
start-container: "{name} 시작"
update-container: "{name} 업데이트"
theme-auto: 시스템 테마 사용
theme-light: 밝은 테마로 전환
theme-dark: 어두운 테마로 전환
toggle-compact: 컴팩트 모드 전환
toggle-timestamps: 타임스탬프 전환
toggle-soft-wrap: 자동 줄바꿈 전환
toggle-stopped: 중지된 컨테이너 전환
toggle-std: stdout/stderr 라벨 전환
toggle-scrollbars: 작은 스크롤바 전환
open-settings: 설정 열기
+16
View File
@@ -409,3 +409,19 @@ cloud-search:
container-removed: "Container is verwijderd"
cta-settings: "Cloud-instellingen"
container-removed-pill: "verwijderd"
command-palette:
section-commands: Opdrachten
restart-container: "{name} opnieuw starten"
stop-container: "{name} stoppen"
start-container: "{name} starten"
update-container: "{name} bijwerken"
theme-auto: Systeemthema gebruiken
theme-light: Overschakelen naar licht thema
theme-dark: Overschakelen naar donker thema
toggle-compact: Compacte modus omschakelen
toggle-timestamps: Tijdstempels omschakelen
toggle-soft-wrap: Zachte terugloop omschakelen
toggle-stopped: Gestopte containers omschakelen
toggle-std: stdout/stderr-labels omschakelen
toggle-scrollbars: Kleinere schuifbalken omschakelen
open-settings: Instellingen openen
+16
View File
@@ -411,3 +411,19 @@ cloud-search:
container-removed: "Kontener został usunięty"
cta-settings: "Ustawienia Cloud"
container-removed-pill: "usunięty"
command-palette:
section-commands: Polecenia
restart-container: Uruchom ponownie {name}
stop-container: Zatrzymaj {name}
start-container: Uruchom {name}
update-container: Zaktualizuj {name}
theme-auto: Użyj motywu systemowego
theme-light: Przełącz na jasny motyw
theme-dark: Przełącz na ciemny motyw
toggle-compact: Przełącz tryb kompaktowy
toggle-timestamps: Przełącz znaczniki czasu
toggle-soft-wrap: Przełącz zawijanie wierszy
toggle-stopped: Przełącz zatrzymane kontenery
toggle-std: Przełącz etykiety stdout/stderr
toggle-scrollbars: Przełącz mniejsze paski przewijania
open-settings: Otwórz ustawienia
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "O container foi excluído"
cta-settings: "Configurações da Cloud"
container-removed-pill: "removido"
command-palette:
section-commands: Comandos
restart-container: Reiniciar {name}
stop-container: Parar {name}
start-container: Iniciar {name}
update-container: Atualizar {name}
theme-auto: Usar tema do sistema
theme-light: Mudar para tema claro
theme-dark: Mudar para tema escuro
toggle-compact: Alternar modo compacto
toggle-timestamps: Alternar carimbos de data/hora
toggle-soft-wrap: Alternar quebra de linha
toggle-stopped: Alternar contêineres parados
toggle-std: Alternar rótulos stdout/stderr
toggle-scrollbars: Alternar barras de rolagem menores
open-settings: Abrir configurações
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "Контейнер был удалён"
cta-settings: "Настройки Cloud"
container-removed-pill: "удалён"
command-palette:
section-commands: Команды
restart-container: Перезапустить {name}
stop-container: Остановить {name}
start-container: Запустить {name}
update-container: Обновить {name}
theme-auto: Использовать системную тему
theme-light: Переключить на светлую тему
theme-dark: Переключить на тёмную тему
toggle-compact: Переключить компактный режим
toggle-timestamps: Переключить метки времени
toggle-soft-wrap: Переключить мягкий перенос
toggle-stopped: Переключить остановленные контейнеры
toggle-std: Переключить метки stdout/stderr
toggle-scrollbars: Переключить уменьшенные полосы прокрутки
open-settings: Открыть настройки
+16
View File
@@ -414,3 +414,19 @@ cloud-search:
container-removed: "Vsebnik je bil izbrisan"
cta-settings: "Nastavitve Cloud"
container-removed-pill: "izbrisano"
command-palette:
section-commands: Ukazi
restart-container: Znova zaženi {name}
stop-container: Ustavi {name}
start-container: Zaženi {name}
update-container: Posodobi {name}
theme-auto: Uporabi sistemsko temo
theme-light: Preklopi na svetlo temo
theme-dark: Preklopi na temno temo
toggle-compact: Preklopi strnjeni način
toggle-timestamps: Preklopi časovne žige
toggle-soft-wrap: Preklopi mehko prelamljanje
toggle-stopped: Preklopi ustavljene vsebnike
toggle-std: Preklopi oznake stdout/stderr
toggle-scrollbars: Preklopi manjše drsnike
open-settings: Odpri nastavitve
+16
View File
@@ -412,3 +412,19 @@ cloud-search:
container-removed: "Konteyner silindi"
cta-settings: "Cloud ayarları"
container-removed-pill: "silindi"
command-palette:
section-commands: Komutlar
restart-container: "{name} yeniden başlat"
stop-container: "{name} durdur"
start-container: "{name} başlat"
update-container: "{name} güncelle"
theme-auto: Sistem temasını kullan
theme-light: Açık temaya geç
theme-dark: Koyu temaya geç
toggle-compact: Kompakt modu aç/kapat
toggle-timestamps: Zaman damgalarını aç/kapat
toggle-soft-wrap: Yumuşak kaydırmayı aç/kapat
toggle-stopped: Durdurulmuş konteynerleri aç/kapat
toggle-std: stdout/stderr etiketlerini aç/kapat
toggle-scrollbars: Daha küçük kaydırma çubuklarını aç/kapat
open-settings: Ayarları
+16
View File
@@ -411,3 +411,19 @@ cloud-search:
container-removed: "容器已被刪除"
cta-settings: "Cloud 設定"
container-removed-pill: "已刪除"
command-palette:
section-commands: 命令
restart-container: 重新啟動 {name}
stop-container: 停止 {name}
start-container: 啟動 {name}
update-container: 更新 {name}
theme-auto: 使用系統主題
theme-light: 切換到淺色主題
theme-dark: 切換到深色主題
toggle-compact: 切換精簡模式
toggle-timestamps: 切換時間戳記
toggle-soft-wrap: 切換軟換行
toggle-stopped: 切換已停止的容器
toggle-std: 切換 stdout/stderr 標籤
toggle-scrollbars: 切換較小的捲軸
open-settings: 開啟設定
+16
View File
@@ -408,3 +408,19 @@ cloud-search:
container-removed: "容器已被删除"
cta-settings: "Cloud 设置"
container-removed-pill: "已删除"
command-palette:
section-commands: 命令
restart-container: 重启 {name}
stop-container: 停止 {name}
start-container: 启动 {name}
update-container: 更新 {name}
theme-auto: 使用系统主题
theme-light: 切换到浅色主题
theme-dark: 切换到深色主题
toggle-compact: 切换紧凑模式
toggle-timestamps: 切换时间戳
toggle-soft-wrap: 切换软换行
toggle-stopped: 切换已停止的容器
toggle-std: 切换 stdout/stderr 标签
toggle-scrollbars: 切换更小的滚动条
open-settings: 打开设置