All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m52s
Status indicators: - Session.status field tracks connected/disconnected state - Listens for ssh:close and ssh:exit backend events - Tab dot turns red when connection drops (green=SSH, blue=RDP, red=dead) Draggable tabs: - HTML5 drag-and-drop on tab buttons - Blue left-border indicator shows drop target - moveSession() in store reorders the sessions array Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95 lines
2.7 KiB
Vue
95 lines
2.7 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[];
|
|
/** Connection status — drives the dot colour. */
|
|
status?: "connected" | "disconnected";
|
|
}>();
|
|
|
|
/** Green=connected SSH, blue=connected RDP, red=disconnected. */
|
|
const protocolDotClass = computed(() => {
|
|
if (props.status === "disconnected") return "bg-[#f85149]";
|
|
return 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>
|