client/web: split login from nodeUpdate
This creates a new /api/up endpoint which is exposed in the login client, and is solely focused on logging in. Login has been removed from the nodeUpdate endpoint. This also adds support in the LoginClientView for a stopped node that just needs to reconnect, but not necessarily reauthenticate. This follows the same pattern in `tailscale up` of just setting the WantRunning user pref. Updates tailscale/corp#14335 Signed-off-by: Will Norris <will@tailscale.com>
This commit is contained in:
@ -3,7 +3,7 @@ import React, { useEffect } from "react"
|
||||
import LoginToggle from "src/components/login-toggle"
|
||||
import DeviceDetailsView from "src/components/views/device-details-view"
|
||||
import HomeView from "src/components/views/home-view"
|
||||
import LoginClientView from "src/components/views/login-client-view"
|
||||
import LoginView from "src/components/views/login-view"
|
||||
import SSHView from "src/components/views/ssh-view"
|
||||
import { UpdatingView } from "src/components/views/updating-view"
|
||||
import useAuth, { AuthResponse } from "src/hooks/auth"
|
||||
@ -39,12 +39,11 @@ function WebClient({
|
||||
|
||||
return !data ? (
|
||||
<div className="text-center py-14">Loading...</div>
|
||||
) : data.Status === "NeedsLogin" || data.Status === "NoState" ? (
|
||||
) : data.Status === "NeedsLogin" ||
|
||||
data.Status === "NoState" ||
|
||||
data.Status === "Stopped" ? (
|
||||
// Client not on a tailnet, render login.
|
||||
<LoginClientView
|
||||
data={data}
|
||||
onLoginClick={() => updateNode({ Reauthenticate: true })}
|
||||
/>
|
||||
<LoginView data={data} refreshData={refreshData} />
|
||||
) : (
|
||||
// Otherwise render the new web client.
|
||||
<>
|
||||
|
@ -1,22 +1,45 @@
|
||||
import React from "react"
|
||||
import React, { useCallback } from "react"
|
||||
import { apiFetch } from "src/api"
|
||||
import { NodeData } from "src/hooks/node-data"
|
||||
import { ReactComponent as TailscaleIcon } from "src/icons/tailscale-icon.svg"
|
||||
|
||||
/**
|
||||
* LoginClientView is rendered when the client is not authenticated
|
||||
* LoginView is rendered when the client is not authenticated
|
||||
* to a tailnet.
|
||||
*/
|
||||
export default function LoginClientView({
|
||||
export default function LoginView({
|
||||
data,
|
||||
onLoginClick,
|
||||
refreshData,
|
||||
}: {
|
||||
data: NodeData
|
||||
onLoginClick: () => void
|
||||
refreshData: () => void
|
||||
}) {
|
||||
const login = useCallback(
|
||||
(opt: TailscaleUpOptions) => {
|
||||
tailscaleUp(opt).then(refreshData)
|
||||
},
|
||||
[refreshData]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="mb-8 py-6 px-8 bg-white rounded-md shadow-2xl">
|
||||
<TailscaleIcon className="my-2 mb-8" />
|
||||
{data.IP ? (
|
||||
{data.Status == "Stopped" ? (
|
||||
<>
|
||||
<div className="mb-6">
|
||||
<h3 className="text-3xl font-semibold mb-3">Connect</h3>
|
||||
<p className="text-gray-700">
|
||||
Your device is disconnected from Tailscale.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => login({})}
|
||||
className="button button-blue w-full mb-4"
|
||||
>
|
||||
Connect to Tailscale
|
||||
</button>
|
||||
</>
|
||||
) : data.IP ? (
|
||||
<>
|
||||
<div className="mb-6">
|
||||
<p className="text-gray-700">
|
||||
@ -33,7 +56,7 @@ export default function LoginClientView({
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={onLoginClick}
|
||||
onClick={() => login({ Reauthenticate: true })}
|
||||
className="button button-blue w-full mb-4"
|
||||
>
|
||||
Reauthenticate
|
||||
@ -53,7 +76,7 @@ export default function LoginClientView({
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={onLoginClick}
|
||||
onClick={() => login({ Reauthenticate: true })}
|
||||
className="button button-blue w-full mb-4"
|
||||
>
|
||||
Log In
|
||||
@ -63,3 +86,18 @@ export default function LoginClientView({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type TailscaleUpOptions = {
|
||||
Reauthenticate?: boolean // force reauthentication
|
||||
}
|
||||
|
||||
function tailscaleUp(options: TailscaleUpOptions) {
|
||||
return apiFetch("/up", "POST", options)
|
||||
.then((r) => r.json())
|
||||
.then((d) => {
|
||||
d.url && window.open(d.url, "_blank")
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("Failed to login:", e)
|
||||
})
|
||||
}
|
@ -47,8 +47,6 @@ export type UserProfile = {
|
||||
export type NodeUpdate = {
|
||||
AdvertiseRoutes?: string
|
||||
AdvertiseExitNode?: boolean
|
||||
Reauthenticate?: boolean
|
||||
ForceLogout?: boolean
|
||||
}
|
||||
|
||||
export type PrefsUpdate = {
|
||||
@ -107,10 +105,6 @@ export default function useNodeData() {
|
||||
if (err) {
|
||||
throw new Error(err)
|
||||
}
|
||||
const url = r["url"]
|
||||
if (url) {
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
refreshData()
|
||||
})
|
||||
.catch((err) => {
|
||||
|
Reference in New Issue
Block a user