wraith/src/components/session/TabBadge.vue
Vantz Stockwell 0cd4cc0f64 feat: Phase 5 complete — themes, editor, shortcuts, workspace, settings
Theme service: 7 built-in themes seeded from Rust, ThemePicker
loads from backend. Workspace service: save/load snapshots, crash
recovery detection. SettingsModal: full port with Tauri invoke.
CommandPalette, HostKeyDialog, ConnectionEditDialog all ported.

CodeMirror editor: inline above terminal, reads/writes via SFTP.
Full keyboard shortcuts: Ctrl+K/W/Tab/Shift+Tab/1-9/B/F.
Terminal search bar via Ctrl+F (SearchAddon).
Tab badges: protocol dots, ROOT warning, environment pills.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 16:36:06 -04:00

92 lines
2.5 KiB
Vue

<template>
<span class="flex items-center gap-1">
<!-- Protocol dot -->
<span
class="w-1.5 h-1.5 rounded-full shrink-0"
:class="protocolDotClass"
:title="protocol === 'ssh' ? 'SSH' : 'RDP'"
/>
<!-- ROOT warning dot -->
<span
v-if="isRoot"
class="w-1.5 h-1.5 rounded-full bg-[#f0883e] shrink-0"
title="Running as root / Administrator"
/>
<!-- Environment pills -->
<span
v-for="tag in envTags"
:key="tag"
class="px-1 py-0.5 text-[9px] font-semibold rounded leading-none shrink-0"
:class="envTagClass(tag)"
>
{{ tag }}
</span>
</span>
</template>
<script setup lang="ts">
import { computed } from "vue";
const props = defineProps<{
/** Connection protocol drives the protocol-dot colour. */
protocol: "ssh" | "rdp";
/** Username from the active session (if known). */
username?: string;
/** Raw tags from the connection record. */
tags?: string[];
}>();
/** Green for SSH, blue for RDP. */
const protocolDotClass = computed(() =>
props.protocol === "ssh" ? "bg-[#3fb950]" : "bg-[#1f6feb]",
);
/** True when the session is running as root or Administrator. */
const isRoot = computed(() => {
if (props.username === "root" || props.username === "Administrator") return true;
// Also flag if a tag explicitly marks the session as root
return props.tags?.some((t) => t === "root" || t === "Administrator") ?? false;
});
/**
* Environment tags derived from the connection's tag list.
* Only surfaces recognised env labels — ignore noise like username tags.
*/
const envTags = computed<string[]>(() => {
if (!props.tags?.length) return [];
return props.tags.filter((t) => {
const u = t.toUpperCase();
return (
u === "PROD" ||
u === "PRODUCTION" ||
u === "DEV" ||
u === "DEVELOPMENT" ||
u === "STAGING" ||
u === "STG" ||
u === "TEST" ||
u === "QA"
);
});
});
/** Tailwind classes for an individual environment pill. */
function envTagClass(tag: string): string {
const u = tag.toUpperCase();
if (u === "PROD" || u === "PRODUCTION") {
return "bg-[#da3633]/20 text-[#f85149]";
}
if (u === "DEV" || u === "DEVELOPMENT") {
return "bg-[#238636]/20 text-[#3fb950]";
}
if (u === "STAGING" || u === "STG") {
return "bg-[#9e6a03]/20 text-[#d29922]";
}
if (u === "TEST" || u === "QA") {
return "bg-[#1f6feb]/20 text-[#58a6ff]";
}
return "bg-[var(--wraith-bg-tertiary)] text-[var(--wraith-text-muted)]";
}
</script>