mirror of https://github.com/tailscale/tailscale/
client/web: remove legacy-client-view.tsx
Updates #10261 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>pull/10273/head
parent
055394f3be
commit
96ad9b6138
@ -1,232 +0,0 @@
|
|||||||
import cx from "classnames"
|
|
||||||
import React from "react"
|
|
||||||
import { apiFetch } from "src/api"
|
|
||||||
import { NodeData, NodeUpdate } from "src/hooks/node-data"
|
|
||||||
|
|
||||||
// TODO(tailscale/corp#13775): legacy.tsx contains a set of components
|
|
||||||
// that (crudely) implement the pre-2023 web client. These are implemented
|
|
||||||
// purely to ease migration to the new React-based web client, and will
|
|
||||||
// eventually be completely removed.
|
|
||||||
|
|
||||||
export default function LegacyClientView({
|
|
||||||
data,
|
|
||||||
refreshData,
|
|
||||||
updateNode,
|
|
||||||
}: {
|
|
||||||
data: NodeData
|
|
||||||
refreshData: () => void
|
|
||||||
updateNode: (update: NodeUpdate) => void
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="container max-w-lg mx-auto mb-8 py-6 px-8 bg-white rounded-md shadow-2xl">
|
|
||||||
<Header data={data} refreshData={refreshData} updateNode={updateNode} />
|
|
||||||
<IP data={data} />
|
|
||||||
{data.Status === "NeedsMachineAuth" ? (
|
|
||||||
<div className="mb-4">
|
|
||||||
This device is authorized, but needs approval from a network admin
|
|
||||||
before it can connect to the network.
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div className="mb-4">
|
|
||||||
<p>
|
|
||||||
You are connected! Access this device over Tailscale using the
|
|
||||||
device name or IP address above.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className={cx("button button-medium mb-4", {
|
|
||||||
"button-red": data.AdvertiseExitNode,
|
|
||||||
"button-blue": !data.AdvertiseExitNode,
|
|
||||||
})}
|
|
||||||
id="enabled"
|
|
||||||
onClick={() =>
|
|
||||||
updateNode({ AdvertiseExitNode: !data.AdvertiseExitNode })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{data.AdvertiseExitNode
|
|
||||||
? "Stop advertising Exit Node"
|
|
||||||
: "Advertise as Exit Node"}
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Header({
|
|
||||||
data,
|
|
||||||
refreshData,
|
|
||||||
updateNode,
|
|
||||||
}: {
|
|
||||||
data: NodeData
|
|
||||||
refreshData: () => void
|
|
||||||
updateNode: (update: NodeUpdate) => void
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<header className="flex justify-between items-center min-width-0 py-2 mb-8">
|
|
||||||
<svg
|
|
||||||
width="26"
|
|
||||||
height="26"
|
|
||||||
viewBox="0 0 23 23"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className="flex-shrink-0 mr-4"
|
|
||||||
>
|
|
||||||
<circle
|
|
||||||
opacity="0.2"
|
|
||||||
cx="3.4"
|
|
||||||
cy="3.25"
|
|
||||||
r="2.7"
|
|
||||||
fill="currentColor"
|
|
||||||
></circle>
|
|
||||||
<circle cx="3.4" cy="11.3" r="2.7" fill="currentColor"></circle>
|
|
||||||
<circle
|
|
||||||
opacity="0.2"
|
|
||||||
cx="3.4"
|
|
||||||
cy="19.5"
|
|
||||||
r="2.7"
|
|
||||||
fill="currentColor"
|
|
||||||
></circle>
|
|
||||||
<circle cx="11.5" cy="11.3" r="2.7" fill="currentColor"></circle>
|
|
||||||
<circle cx="11.5" cy="19.5" r="2.7" fill="currentColor"></circle>
|
|
||||||
<circle
|
|
||||||
opacity="0.2"
|
|
||||||
cx="11.5"
|
|
||||||
cy="3.25"
|
|
||||||
r="2.7"
|
|
||||||
fill="currentColor"
|
|
||||||
></circle>
|
|
||||||
<circle
|
|
||||||
opacity="0.2"
|
|
||||||
cx="19.5"
|
|
||||||
cy="3.25"
|
|
||||||
r="2.7"
|
|
||||||
fill="currentColor"
|
|
||||||
></circle>
|
|
||||||
<circle cx="19.5" cy="11.3" r="2.7" fill="currentColor"></circle>
|
|
||||||
<circle
|
|
||||||
opacity="0.2"
|
|
||||||
cx="19.5"
|
|
||||||
cy="19.5"
|
|
||||||
r="2.7"
|
|
||||||
fill="currentColor"
|
|
||||||
></circle>
|
|
||||||
</svg>
|
|
||||||
<div className="flex items-center justify-end space-x-2 w-2/3">
|
|
||||||
{data.Profile &&
|
|
||||||
data.Status !== "NoState" &&
|
|
||||||
data.Status !== "NeedsLogin" && (
|
|
||||||
<>
|
|
||||||
<div className="text-right w-full leading-4">
|
|
||||||
<h4 className="truncate leading-normal">
|
|
||||||
{data.Profile.LoginName}
|
|
||||||
</h4>
|
|
||||||
<div className="text-xs text-gray-500 text-right">
|
|
||||||
<button
|
|
||||||
onClick={() => updateNode({ Reauthenticate: true })}
|
|
||||||
className="hover:text-gray-700"
|
|
||||||
>
|
|
||||||
Switch account
|
|
||||||
</button>{" "}
|
|
||||||
|{" "}
|
|
||||||
<button
|
|
||||||
onClick={() => updateNode({ Reauthenticate: true })}
|
|
||||||
className="hover:text-gray-700"
|
|
||||||
>
|
|
||||||
Reauthenticate
|
|
||||||
</button>{" "}
|
|
||||||
|{" "}
|
|
||||||
<button
|
|
||||||
onClick={() =>
|
|
||||||
apiFetch("/local/v0/logout", "POST")
|
|
||||||
.then(refreshData)
|
|
||||||
.catch((err) => alert("Logout failed: " + err.message))
|
|
||||||
}
|
|
||||||
className="hover:text-gray-700"
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="relative flex-shrink-0 w-8 h-8 rounded-full overflow-hidden">
|
|
||||||
{data.Profile.ProfilePicURL ? (
|
|
||||||
<div
|
|
||||||
className="w-8 h-8 flex pointer-events-none rounded-full bg-gray-200"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${data.Profile.ProfilePicURL})`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="w-8 h-8 flex pointer-events-none rounded-full border border-gray-400 border-dashed" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function IP(props: { data: NodeData }) {
|
|
||||||
const { data } = props
|
|
||||||
|
|
||||||
if (!data.IP) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="border border-gray-200 bg-gray-50 rounded-md p-2 pl-3 pr-3 width-full flex items-center justify-between">
|
|
||||||
<div className="flex items-center min-width-0">
|
|
||||||
<svg
|
|
||||||
className="flex-shrink-0 text-gray-600 mr-3 ml-1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
|
|
||||||
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
|
|
||||||
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
|
||||||
<line x1="6" y1="18" x2="6.01" y2="18"></line>
|
|
||||||
</svg>
|
|
||||||
<h4 className="font-semibold truncate mr-2">
|
|
||||||
{data.DeviceName || "Your device"}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<h5>{data.IP}</h5>
|
|
||||||
</div>
|
|
||||||
<p className="mt-1 ml-1 mb-6 text-xs text-gray-600">
|
|
||||||
Debug info: Tailscale {data.IPNVersion}, tun={data.TUNMode.toString()}
|
|
||||||
{data.IsSynology && (
|
|
||||||
<>
|
|
||||||
, DSM{data.DSMVersion}
|
|
||||||
{data.TUNMode || (
|
|
||||||
<>
|
|
||||||
{" "}
|
|
||||||
(
|
|
||||||
<a
|
|
||||||
href="https://tailscale.com/kb/1152/synology-outbound/"
|
|
||||||
className="link-underline text-gray-600"
|
|
||||||
target="_blank"
|
|
||||||
aria-label="Configure outbound synology traffic"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
outgoing access not configured
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue