client/web: add copyable components throughout UI

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>
This commit is contained in:
Sonia Appasamy
2023-12-05 10:09:33 -05:00
committed by Sonia Appasamy
parent 650c67a0a1
commit a95b3cbfa8
19 changed files with 850 additions and 26 deletions

View File

@ -2,18 +2,17 @@
// SPDX-License-Identifier: BSD-3-Clause
import { useCallback, useEffect, useMemo, useState } from "react"
import { apiFetch, setUnraidCsrfToken } from "src/api"
import { apiFetch, incrementMetric, setUnraidCsrfToken } from "src/api"
import { ExitNode, noExitNode, runAsExitNode } from "src/hooks/exit-nodes"
import { VersionInfo } from "src/hooks/self-update"
import { assertNever } from "src/util"
import { incrementMetric, MetricName } from "src/api"
import { assertNever } from "src/utils/util"
export type NodeData = {
Profile: UserProfile
Status: NodeState
DeviceName: string
OS: string
IP: string
IPv4: string
IPv6: string
ID: string
KeyExpiry: string
@ -177,7 +176,11 @@ export default function useNodeData() {
const updateMetrics = () => {
// only update metrics if values have changed
if (data?.AdvertisingExitNode !== d.AdvertiseExitNode) {
incrementMetric(d.AdvertiseExitNode ? "web_client_advertise_exitnode_enable" : "web_client_advertise_exitnode_disable")
incrementMetric(
d.AdvertiseExitNode
? "web_client_advertise_exitnode_enable"
: "web_client_advertise_exitnode_disable"
)
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
import { useRawToasterForHook } from "src/ui/toaster"
/**
* useToaster provides a mechanism to display toasts. It returns an object with
* methods to show, dismiss, or clear all toasts:
*
* const toastKey = toaster.show({ message: "Hello world" })
* toaster.dismiss(toastKey)
* toaster.clear()
*
*/
const useToaster = useRawToasterForHook
export default useToaster