Files
CodeNomad/packages/ui/src/components/instance-tab.tsx
2026-02-12 14:57:40 +00:00

83 lines
2.6 KiB
TypeScript

import { Component, createMemo } from "solid-js"
import type { Instance } from "../types/instance"
import { getInstanceSessionIndicatorStatus } from "../stores/session-status"
import { FolderOpen, ShieldAlert, X } from "lucide-solid"
import { useI18n } from "../lib/i18n"
interface InstanceTabProps {
instance: Instance
active: boolean
onSelect: () => void
onClose: () => void
}
function getPathBasename(path: string): string {
// Instance folders can be POSIX-like (/Users/...) on macOS/Linux or Windows-like (C:\Users\...).
// Normalize by trimming trailing separators and then splitting on both '/' and '\\'.
const normalized = path.replace(/[\\/]+$/, "")
return normalized.split(/[\\/]/).pop() || path
}
const InstanceTab: Component<InstanceTabProps> = (props) => {
const { t } = useI18n()
const aggregatedStatus = createMemo(() => getInstanceSessionIndicatorStatus(props.instance.id))
const statusClassName = createMemo(() => {
const status = aggregatedStatus()
return status === "permission" ? "session-permission" : `session-${status}`
})
const statusTitle = createMemo(() => {
switch (aggregatedStatus()) {
case "permission":
return t("instanceTab.status.permission")
case "compacting":
return t("instanceTab.status.compacting")
case "working":
return t("instanceTab.status.working")
default:
return t("instanceTab.status.idle")
}
})
return (
<div class="group">
<button
class={`tab-base ${props.active ? "tab-active" : "tab-inactive"}`}
onClick={props.onSelect}
title={props.instance.folder}
role="tab"
aria-selected={props.active}
>
<FolderOpen class="w-4 h-4 flex-shrink-0" />
<span class="tab-label">
{getPathBasename(props.instance.folder)}
</span>
<span
class={`status-indicator session-status ml-auto ${statusClassName()}`}
title={statusTitle()}
aria-label={t("instanceTab.status.ariaLabel", { status: statusTitle() })}
>
{aggregatedStatus() === "permission" ? (
<ShieldAlert class="w-3.5 h-3.5" aria-hidden="true" />
) : (
<span class="status-dot" />
)}
</span>
<span
class="tab-close"
onClick={(e) => {
e.stopPropagation()
props.onClose()
}}
role="button"
tabIndex={0}
aria-label={t("instanceTab.actions.close.ariaLabel")}
>
<X class="w-3 h-3" />
</span>
</button>
</div>
)
}
export default InstanceTab