client/web: show manage button in readonly view

We render the readonly view in two situations:
- the client is in login mode, and the device is connected
- the client is in manage mode, but the user does not yet have a session

If the user is not authenticated, and they are not currently on the
Tailscale IP address, render a "Manage" button that will take them to
the Tailcale IP of the device and immediately start check mode.

Still to do is detecting if they have connectivity to the Tailscale IP,
and disabling the button if not.

Updates tailscale/corp#14335

Signed-off-by: Will Norris <will@tailscale.com>
pull/10149/head
Will Norris 8 months ago committed by Will Norris
parent 96a80fcce3
commit 3e9026efda

@ -1,5 +1,5 @@
import React from "react"
import { AuthResponse, AuthType, SessionsCallbacks } from "src/hooks/auth"
import { AuthResponse, AuthType } from "src/hooks/auth"
import { NodeData } from "src/hooks/node-data"
import { ReactComponent as ConnectedDeviceIcon } from "src/icons/connected-device.svg"
import { ReactComponent as TailscaleLogo } from "src/icons/tailscale-logo.svg"
@ -17,11 +17,11 @@ import ProfilePic from "src/ui/profile-pic"
export default function ReadonlyClientView({
data,
auth,
sessions,
newSession,
}: {
data: NodeData
auth?: AuthResponse
sessions: SessionsCallbacks
newSession: () => Promise<void>
}) {
return (
<>
@ -51,18 +51,22 @@ export default function ReadonlyClientView({
<div className="text-sm leading-tight">{data.IP}</div>
</div>
</div>
{auth?.authNeeded == AuthType.tailscale && (
<button
className="button button-blue ml-6"
onClick={() => {
sessions
.new()
.then((url) => window.open(url, "_blank"))
.then(() => sessions.wait())
}}
>
{auth?.authNeeded == AuthType.tailscale ? (
<button className="button button-blue ml-6" onClick={newSession}>
Access
</button>
) : (
window.location.hostname != data.IP && (
// TODO: check connectivity to tailscale IP
<button
className="button button-blue ml-6"
onClick={() => {
window.location.href = `http://${data.IP}:5252/?check=now`
}}
>
Manage
</button>
)
)}
</div>
</div>

@ -11,11 +11,6 @@ export type AuthResponse = {
authNeeded?: AuthType
}
export type SessionsCallbacks = {
new: () => Promise<string> // creates new auth session and returns authURL
wait: () => Promise<void> // blocks until auth is completed
}
// useAuth reports and refreshes Tailscale auth status
// for the web client.
export default function useAuth() {
@ -50,15 +45,13 @@ export default function useAuth() {
const newSession = useCallback(() => {
return apiFetch("/auth/session/new", "GET")
.then((r) => r.json())
.then((d) => d.authUrl)
.catch((error) => {
console.error(error)
.then((d) => {
if (d.authUrl) {
window.open(d.authUrl, "_blank")
// refresh data when auth complete
apiFetch("/auth/session/wait", "GET").then(() => loadAuth())
}
})
}, [])
const waitForSessionCompletion = useCallback(() => {
return apiFetch("/auth/session/wait", "GET")
.then(() => loadAuth()) // refresh auth data
.catch((error) => {
console.error(error)
})
@ -66,14 +59,14 @@ export default function useAuth() {
useEffect(() => {
loadAuth()
if (new URLSearchParams(window.location.search).get("check") == "now") {
newSession()
}
}, [])
return {
data,
loading,
sessions: {
new: newSession,
wait: waitForSessionCompletion,
},
newSession,
}
}

Loading…
Cancel
Save