summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/components/server/server-row.tsx
blob: 12dcebfa9715cd80ea5619200b7bc5270f01ce0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { Tooltip } from "@opencode-ai/ui/tooltip"
import {
  createEffect,
  createMemo,
  createSignal,
  type JSXElement,
  onCleanup,
  onMount,
  type ParentProps,
  Show,
} from "solid-js"
import { type ServerConnection, serverDisplayName } from "@/context/server"
import type { ServerHealth } from "@/utils/server-health"

interface ServerRowProps extends ParentProps {
  conn: ServerConnection.Any
  status?: ServerHealth
  class?: string
  nameClass?: string
  versionClass?: string
  dimmed?: boolean
  badge?: JSXElement
}

export function ServerRow(props: ServerRowProps) {
  const [truncated, setTruncated] = createSignal(false)
  let nameRef: HTMLSpanElement | undefined
  let versionRef: HTMLSpanElement | undefined
  const name = createMemo(() => serverDisplayName(props.conn))

  const check = () => {
    const nameTruncated = nameRef ? nameRef.scrollWidth > nameRef.clientWidth : false
    const versionTruncated = versionRef ? versionRef.scrollWidth > versionRef.clientWidth : false
    setTruncated(nameTruncated || versionTruncated)
  }

  createEffect(() => {
    name()
    props.conn.http.url
    props.status?.version
    queueMicrotask(check)
  })

  onMount(() => {
    check()
    if (typeof ResizeObserver !== "function") return
    const observer = new ResizeObserver(check)
    if (nameRef) observer.observe(nameRef)
    if (versionRef) observer.observe(versionRef)
    onCleanup(() => observer.disconnect())
  })

  const tooltipValue = () => (
    <span class="flex items-center gap-2">
      <span>{name()}</span>
      <Show when={props.status?.version}>
        <span class="text-text-invert-base">{props.status?.version}</span>
      </Show>
    </span>
  )

  return (
    <Tooltip value={tooltipValue()} placement="top" inactive={!truncated()}>
      <div class={props.class} classList={{ "opacity-50": props.dimmed }}>
        <div
          classList={{
            "size-1.5 rounded-full shrink-0": true,
            "bg-icon-success-base": props.status?.healthy === true,
            "bg-icon-critical-base": props.status?.healthy === false,
            "bg-border-weak-base": props.status === undefined,
          }}
        />
        <span ref={nameRef} class={props.nameClass ?? "truncate"}>
          {name()}
        </span>
        <Show when={props.status?.version}>
          <span ref={versionRef} class={props.versionClass ?? "text-text-weak text-14-regular truncate"}>
            {props.status?.version}
          </span>
        </Show>
        {props.badge}
        {props.children}
      </div>
    </Tooltip>
  )
}