diff --git a/client/web/package.json b/client/web/package.json index 5c7b33add..a986265d8 100644 --- a/client/web/package.json +++ b/client/web/package.json @@ -8,6 +8,7 @@ }, "private": true, "dependencies": { + "@radix-ui/react-popover": "^1.0.6", "classnames": "^2.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/client/web/qnap.go b/client/web/qnap.go index 07145a77c..9bde64bf5 100644 --- a/client/web/qnap.go +++ b/client/web/qnap.go @@ -20,16 +20,16 @@ import ( // authorizeQNAP authenticates the logged-in QNAP user and verifies that they // are authorized to use the web client. // If the user is not authorized to use the client, an error is returned. -func authorizeQNAP(r *http.Request) (ar authResponse, err error) { +func authorizeQNAP(r *http.Request) (authorized bool, err error) { _, resp, err := qnapAuthn(r) if err != nil { - return ar, err + return false, err } if resp.IsAdmin == 0 { - return ar, errors.New("user is not an admin") + return false, errors.New("user is not an admin") } - return authResponse{OK: true}, nil + return true, nil } type qnapAuthResponse struct { diff --git a/client/web/src/components/app.tsx b/client/web/src/components/app.tsx index 41f5e5c2e..95d19e70e 100644 --- a/client/web/src/components/app.tsx +++ b/client/web/src/components/app.tsx @@ -1,22 +1,21 @@ import cx from "classnames" 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 LegacyClientView from "src/components/views/legacy-client-view" import LoginClientView from "src/components/views/login-client-view" -import ManagementClientView from "src/components/views/management-client-view" -import ReadonlyClientView from "src/components/views/readonly-client-view" import useAuth, { AuthResponse } from "src/hooks/auth" -import useNodeData, { NodeData, NodeUpdate } from "src/hooks/node-data" +import useNodeData, { NodeData } from "src/hooks/node-data" import { ReactComponent as TailscaleIcon } from "src/icons/tailscale-icon.svg" -import ProfilePic from "src/ui/profile-pic" import { Link, Route, Router, Switch, useLocation } from "wouter" -import DeviceDetailsView from "./views/device-details-view" export default function App() { const { data: auth, loading: loadingAuth, newSession } = useAuth() return (
- {loadingAuth ? ( + {loadingAuth || !auth ? (
Loading...
// TODO(sonia): add a loading view ) : ( @@ -29,7 +28,7 @@ function WebClient({ auth, newSession, }: { - auth?: AuthResponse + auth: AuthResponse newSession: () => Promise }) { const { data, refreshData, updateNode } = useNodeData() @@ -37,36 +36,44 @@ function WebClient({ refreshData() }, [auth, refreshData]) - if (!data) { - return
Loading...
// TODO(sonia): add a loading view - } - - return ( + return !data ? ( +
Loading...
+ ) : data.Status === "NeedsLogin" || data.Status === "NoState" ? ( + // Client not on a tailnet, render login. + updateNode({ Reauthenticate: true })} + /> + ) : data.DebugMode !== "full" && data.DebugMode !== "login" ? ( + // Render legacy client interface. + <> + + {/* TODO: add license to new client */} +