Pools: Anzeigename von Pool-ID (UUID-Ordner) getrennt + Umbenennen; API-Keys in Keychain/Keyring, Datei-Fallback nur nach Rückfrage

This commit is contained in:
marcus.hinz
2026-07-05 12:16:16 +02:00
parent 23aa315b8f
commit be6c56d7eb
6 changed files with 855 additions and 148 deletions
+54 -6
View File
@@ -12,6 +12,7 @@ interface Project {
}
interface Pool {
id: string;
name: string;
credentialType: string;
hasCredentials: boolean;
@@ -19,10 +20,16 @@ interface Pool {
function poolReady(p: Project): boolean {
if (!p.pool) return false;
const pool = pools.value.find((x) => x.name === p.pool);
const pool = pools.value.find((x) => x.id === p.pool);
return pool !== undefined && pool.hasCredentials;
}
// Projekt-Configs tragen die Pool-ID; angezeigt wird der Name aus pool.json.
function poolName(id: string | null): string | null {
if (!id) return null;
return pools.value.find((x) => x.id === id)?.name ?? id;
}
function startBlockedReason(p: Project): string | undefined {
if (poolReady(p)) return undefined;
return p.pool ? "projects.needsKey" : "projects.needsPool";
@@ -32,6 +39,35 @@ const projects = ref<Project[]>([]);
const pools = ref<Pool[]>([]);
const error = ref("");
// data-URLs pro (Projekt, Icon-Pfad) — Fehlversuche werden als "" gemerkt,
// damit der 3s-Poll nicht dieselbe Fehlermeldung wiederholt.
const icons = ref<Record<string, string>>({});
function iconKey(p: Project): string | null {
return p.terminal.icon ? `${p.name}:${p.terminal.icon}` : null;
}
function projIcon(p: Project): string | undefined {
const key = iconKey(p);
return key ? icons.value[key] || undefined : undefined;
}
async function loadIcons() {
for (const p of projects.value) {
const key = iconKey(p);
if (!key || key in icons.value) continue;
try {
const data = await invoke<string | null>("project_icon", {
project: p.name,
});
icons.value[key] = data ?? "";
} catch (e) {
error.value = String(e);
icons.value[key] = "";
}
}
}
async function refresh() {
try {
projects.value = await invoke<Project[]>("list_projects");
@@ -40,6 +76,7 @@ async function refresh() {
} catch (e) {
error.value = String(e);
}
await loadIcons();
}
async function stop(project: Project) {
@@ -103,6 +140,14 @@ const THEME_NAMES: [string, string][] = [
["solarized-dark", "Solarized Dark"],
["gruvbox", "Gruvbox"],
["one-dark", "One Dark"],
["nord", "Nord"],
["tokyo-night", "Tokyo Night"],
["monokai", "Monokai"],
["rose-pine", "Rosé Pine"],
["everforest", "Everforest"],
["solarized-light", "Solarized Light"],
["catppuccin-latte", "Catppuccin Latte"],
["one-light", "One Light"],
];
interface TerminalSettings {
@@ -292,13 +337,16 @@ onUnmounted(() => window.clearInterval(timer));
<span class="dot" :class="{ on: p.running }"></span>
</td>
<td class="cell-name">
<strong>{{ p.name }}</strong>
<span class="name-row">
<img v-if="projIcon(p)" class="proj-icon" :src="projIcon(p)" />
<strong>{{ p.name }}</strong>
</span>
<small>{{ p.path }}</small>
</td>
<td>
<select :value="p.pool ?? ''" @change="assign(p, $event)">
<option value="" disabled>{{ $t("projects.noPool") }}</option>
<option v-for="pool in pools" :key="pool.name" :value="pool.name">
<option v-for="pool in pools" :key="pool.id" :value="pool.id">
{{ pool.name }}
</option>
</select>
@@ -349,7 +397,7 @@ onUnmounted(() => window.clearInterval(timer));
{{ $t("projects.pool") }}
<select v-model="wizard.pool">
<option value="">{{ $t("projects.noPool") }}</option>
<option v-for="pool in pools" :key="pool.name" :value="pool.name">
<option v-for="pool in pools" :key="pool.id" :value="pool.id">
{{ pool.name }}
</option>
</select>
@@ -493,9 +541,9 @@ onUnmounted(() => window.clearInterval(timer));
<h3>{{ $t("projects.stillRunning", { name: pending.name }) }}</h3>
<p>{{ $t("projects.poolChangeSaved") }}</p>
<div class="pools">
<span class="chip">{{ pending.from ?? $t("projects.noPoolAssigned") }}</span>
<span class="chip">{{ poolName(pending.from) ?? $t("projects.noPoolAssigned") }}</span>
<span class="arrow"></span>
<span class="chip new">{{ pending.to }}</span>
<span class="chip new">{{ poolName(pending.to) }}</span>
</div>
<p class="hint">{{ $t("projects.restartHint") }}</p>
<div class="actions">