mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-19 05:21:27 +02:00
Updates the IP address on home view to open a copyable list of node addresses on click. And makes various values on the details view copyable text items, mirroring the machine admin panel table. As part of these changes, pulls the AddressCard, NiceIP and QuickCopy components from the admin panel, with the AddressCard slightly modified to avoid needing to also pull in the CommandLine component. A new toaster interface is also added, allowing us to display success and failure toasts throughout the UI. The toaster code is slightly modified from it's admin form to avoid the need for some excess libraries. Updates #10261 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
import cx from "classnames"
|
|
import React from "react"
|
|
import { isTailscaleIPv6 } from "src/utils/util"
|
|
|
|
type Props = {
|
|
ip: string
|
|
className?: string
|
|
}
|
|
|
|
/**
|
|
* NiceIP displays IP addresses with nice truncation.
|
|
*/
|
|
export default function NiceIP(props: Props) {
|
|
const { ip, className } = props
|
|
|
|
if (!isTailscaleIPv6(ip)) {
|
|
return <span className={className}>{ip}</span>
|
|
}
|
|
|
|
const [trimmable, untrimmable] = splitIPv6(ip)
|
|
|
|
return (
|
|
<span
|
|
className={cx("inline-flex justify-start min-w-0 max-w-full", className)}
|
|
>
|
|
{trimmable.length > 0 && (
|
|
<span className="truncate w-fit flex-shrink">{trimmable}</span>
|
|
)}
|
|
<span className="flex-grow-0 flex-shrink-0">{untrimmable}</span>
|
|
</span>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Split an IPv6 address into two pieces, to help with truncating the middle.
|
|
* Only exported for testing purposes. Do not use.
|
|
*/
|
|
export function splitIPv6(ip: string): [string, string] {
|
|
// We want to split the IPv6 address into segments, but not remove the delimiter.
|
|
// So we inject an invalid IPv6 character ("|") as a delimiter into the string,
|
|
// then split on that.
|
|
const parts = ip.replace(/(:{1,2})/g, "|$1").split("|")
|
|
|
|
// Then we find the number of end parts that fits within the character limit,
|
|
// and join them back together.
|
|
const characterLimit = 12
|
|
let characterCount = 0
|
|
let idxFromEnd = 1
|
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
const part = parts[i]
|
|
if (characterCount + part.length > characterLimit) {
|
|
break
|
|
}
|
|
characterCount += part.length
|
|
idxFromEnd++
|
|
}
|
|
|
|
const start = parts.slice(0, -idxFromEnd).join("")
|
|
const end = parts.slice(-idxFromEnd).join("")
|
|
|
|
return [start, end]
|
|
}
|