Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
Go + Wails v3 + Vue 3 + SQLite + FreeRDP3 (purego) 183 tests, 76 source files, 9,910 lines of code Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
114 lines
4.7 KiB
Vue
114 lines
4.7 KiB
Vue
<template>
|
|
<div class="flex items-center bg-[var(--wraith-bg-secondary)] border-b border-[var(--wraith-border)] h-9 shrink-0">
|
|
<!-- Tabs -->
|
|
<div class="flex items-center overflow-x-auto min-w-0">
|
|
<button
|
|
v-for="session in sessionStore.sessions"
|
|
:key="session.id"
|
|
class="group flex items-center gap-2 px-3 h-9 text-xs whitespace-nowrap border-r border-[var(--wraith-border)] transition-all duration-500 cursor-pointer shrink-0"
|
|
:class="[
|
|
session.id === sessionStore.activeSessionId
|
|
? 'bg-[var(--wraith-bg-primary)] text-[var(--wraith-text-primary)] border-b-2 border-b-[var(--wraith-accent-blue)]'
|
|
: 'text-[var(--wraith-text-muted)] hover:text-[var(--wraith-text-secondary)] hover:bg-[var(--wraith-bg-tertiary)]',
|
|
isRootUser(session) ? 'border-t-2 border-t-[#f8514966]' : '',
|
|
]"
|
|
@click="sessionStore.activateSession(session.id)"
|
|
>
|
|
<!-- Protocol icon -->
|
|
<span class="shrink-0">
|
|
<!-- SSH terminal icon -->
|
|
<svg
|
|
v-if="session.protocol === 'ssh'"
|
|
class="w-3.5 h-3.5 text-[#3fb950]"
|
|
viewBox="0 0 16 16"
|
|
fill="currentColor"
|
|
>
|
|
<path d="M0 2.75C0 1.784.784 1 1.75 1h12.5c.966 0 1.75.784 1.75 1.75v10.5A1.75 1.75 0 0 1 14.25 15H1.75A1.75 1.75 0 0 1 0 13.25Zm1.75-.25a.25.25 0 0 0-.25.25v10.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V2.75a.25.25 0 0 0-.25-.25ZM7.25 8a.749.749 0 0 1-.22.53l-2.25 2.25a.749.749 0 1 1-1.06-1.06L5.44 8 3.72 6.28a.749.749 0 1 1 1.06-1.06l2.25 2.25c.141.14.22.331.22.53Zm1.5 1.5h3a.75.75 0 0 1 0 1.5h-3a.75.75 0 0 1 0-1.5Z" />
|
|
</svg>
|
|
<!-- RDP monitor icon -->
|
|
<svg
|
|
v-else
|
|
class="w-3.5 h-3.5 text-[#1f6feb]"
|
|
viewBox="0 0 16 16"
|
|
fill="currentColor"
|
|
>
|
|
<path d="M1.75 2.5h12.5a.25.25 0 0 1 .25.25v7.5a.25.25 0 0 1-.25.25H1.75a.25.25 0 0 1-.25-.25v-7.5a.25.25 0 0 1 .25-.25ZM14.25 1H1.75A1.75 1.75 0 0 0 0 2.75v7.5C0 11.216.784 12 1.75 12h4.388l-.533 1.5H4a.75.75 0 0 0 0 1.5h8a.75.75 0 0 0 0-1.5h-1.605l-.533-1.5h4.388A1.75 1.75 0 0 0 16 10.25v-7.5A1.75 1.75 0 0 0 14.25 1ZM9.112 13.5H6.888l.533-1.5h1.158l.533 1.5Z" />
|
|
</svg>
|
|
</span>
|
|
|
|
<span>{{ session.name }}</span>
|
|
|
|
<!-- Environment tag badges -->
|
|
<template v-if="getSessionTags(session).length > 0">
|
|
<span
|
|
v-for="tag in getSessionTags(session)"
|
|
:key="tag"
|
|
class="px-1 py-0.5 text-[9px] font-semibold rounded leading-none"
|
|
:class="tagClass(tag)"
|
|
>
|
|
{{ tag }}
|
|
</span>
|
|
</template>
|
|
|
|
<!-- Close button -->
|
|
<span
|
|
class="ml-1 opacity-0 group-hover:opacity-100 hover:text-[var(--wraith-accent-red)] transition-opacity"
|
|
@click.stop="sessionStore.closeSession(session.id)"
|
|
>
|
|
×
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- New tab button -->
|
|
<button
|
|
class="flex items-center justify-center w-9 h-9 text-[var(--wraith-text-muted)] hover:text-[var(--wraith-text-primary)] hover:bg-[var(--wraith-bg-tertiary)] transition-colors cursor-pointer shrink-0"
|
|
title="New session"
|
|
>
|
|
+
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useSessionStore, type Session } from "@/stores/session.store";
|
|
import { useConnectionStore } from "@/stores/connection.store";
|
|
|
|
const sessionStore = useSessionStore();
|
|
const connectionStore = useConnectionStore();
|
|
|
|
/** Get tags for a session's underlying connection. */
|
|
function getSessionTags(session: Session): string[] {
|
|
const conn = connectionStore.connections.find((c) => c.id === session.connectionId);
|
|
return conn?.tags ?? [];
|
|
}
|
|
|
|
/** Check if the connection for this session uses the root user. */
|
|
function isRootUser(session: Session): boolean {
|
|
const conn = connectionStore.connections.find((c) => c.id === session.connectionId);
|
|
if (!conn) return false;
|
|
// TODO: Get actual username from the credential or session
|
|
// For now, check mock data — root user detection will come from the session/credential store
|
|
return false;
|
|
}
|
|
|
|
/** Return Tailwind classes for environment tag badges. */
|
|
function tagClass(tag: string): string {
|
|
const t = tag.toUpperCase();
|
|
if (t === "PROD" || t === "PRODUCTION") {
|
|
return "bg-[#da3633]/20 text-[#f85149]";
|
|
}
|
|
if (t === "DEV" || t === "DEVELOPMENT") {
|
|
return "bg-[#238636]/20 text-[#3fb950]";
|
|
}
|
|
if (t === "STAGING" || t === "STG") {
|
|
return "bg-[#9e6a03]/20 text-[#d29922]";
|
|
}
|
|
if (t === "TEST" || t === "QA") {
|
|
return "bg-[#1f6feb]/20 text-[#58a6ff]";
|
|
}
|
|
// Default for other tags
|
|
return "bg-[var(--wraith-bg-tertiary)] text-[var(--wraith-text-muted)]";
|
|
}
|
|
</script>
|