mirror of
https://github.com/openziti/zrok.git
synced 2025-01-05 05:30:16 +01:00
more state store, less random property wiring (#724)
This commit is contained in:
parent
db85823151
commit
544c1757f5
@ -1,16 +1,17 @@
|
|||||||
import {Node} from "@xyflow/react";
|
import {Node} from "@xyflow/react";
|
||||||
import {Grid2, Paper, TableBody, TableContainer, Typography} from "@mui/material";
|
import {Grid2, Typography} from "@mui/material";
|
||||||
import AccountIcon from "@mui/icons-material/Person4";
|
import AccountIcon from "@mui/icons-material/Person4";
|
||||||
import {User} from "./model/user.ts";
|
|
||||||
import PropertyTable from "./PropertyTable.tsx";
|
import PropertyTable from "./PropertyTable.tsx";
|
||||||
import SecretToggle from "./SecretToggle.tsx";
|
import SecretToggle from "./SecretToggle.tsx";
|
||||||
|
import useStore from "./model/store.ts";
|
||||||
|
|
||||||
interface AccountPanelProps {
|
interface AccountPanelProps {
|
||||||
account: Node;
|
account: Node;
|
||||||
user: User;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountPanel = ({ account, user }: AccountPanelProps) => {
|
const AccountPanel = ({ account}: AccountPanelProps) => {
|
||||||
|
const user = useStore((state) => state.user);
|
||||||
|
|
||||||
const customProps = {
|
const customProps = {
|
||||||
token: row => <SecretToggle secret={row.value} />
|
token: row => <SecretToggle secret={row.value} />
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,7 @@ import {Configuration, MetadataApi} from "./api";
|
|||||||
import {mergeVisualOverview, nodesEqual, VisualOverview} from "./model/visualizer.ts";
|
import {mergeVisualOverview, nodesEqual, VisualOverview} from "./model/visualizer.ts";
|
||||||
import {Grid2} from "@mui/material";
|
import {Grid2} from "@mui/material";
|
||||||
import NavBar from "./NavBar.tsx";
|
import NavBar from "./NavBar.tsx";
|
||||||
import {User} from "./model/user.ts";
|
|
||||||
import Visualizer from "./Visualizer.tsx";
|
import Visualizer from "./Visualizer.tsx";
|
||||||
import {Node} from "@xyflow/react";
|
|
||||||
import AccountPanel from "./AccountPanel.tsx";
|
import AccountPanel from "./AccountPanel.tsx";
|
||||||
import EnvironmentPanel from "./EnvironmentPanel.tsx";
|
import EnvironmentPanel from "./EnvironmentPanel.tsx";
|
||||||
import SharePanel from "./SharePanel.tsx";
|
import SharePanel from "./SharePanel.tsx";
|
||||||
@ -13,17 +11,18 @@ import AccessPanel from "./AccessPanel.tsx";
|
|||||||
import useStore from "./model/store.ts";
|
import useStore from "./model/store.ts";
|
||||||
|
|
||||||
interface ApiConsoleProps {
|
interface ApiConsoleProps {
|
||||||
user: User;
|
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ApiConsole = ({ user, logout }: ApiConsoleProps) => {
|
const ApiConsole = ({ logout }: ApiConsoleProps) => {
|
||||||
|
const user = useStore((state) => state.user);
|
||||||
const overview = useStore((state) => state.overview);
|
const overview = useStore((state) => state.overview);
|
||||||
const updateOverview = useStore((state) => state.updateOverview);
|
const updateOverview = useStore((state) => state.updateOverview);
|
||||||
const oldVov = useRef<VisualOverview>(overview);
|
const oldVov = useRef<VisualOverview>(overview);
|
||||||
const [selectedNode, setSelectedNode] = useState(null as Node);
|
const selectedNode = useStore((state) => state.selectedNode);
|
||||||
const [sidePanel, setSidePanel] = useState(<></>);
|
const updateSelectedNode = useStore((state) => state.updateSelectedNode);
|
||||||
const updateEnvironments = useStore((state) => state.updateEnvironments);
|
const updateEnvironments = useStore((state) => state.updateEnvironments);
|
||||||
|
const [sidePanel, setSidePanel] = useState(<></>);
|
||||||
|
|
||||||
const retrieveOverview = () => {
|
const retrieveOverview = () => {
|
||||||
let cfg = new Configuration({
|
let cfg = new Configuration({
|
||||||
@ -90,15 +89,15 @@ const ApiConsole = ({ user, logout }: ApiConsoleProps) => {
|
|||||||
if(selectedNode) {
|
if(selectedNode) {
|
||||||
switch(selectedNode.type) {
|
switch(selectedNode.type) {
|
||||||
case "account":
|
case "account":
|
||||||
setSidePanel(<AccountPanel account={selectedNode} user={user} />);
|
setSidePanel(<AccountPanel account={selectedNode} />);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "environment":
|
case "environment":
|
||||||
setSidePanel(<EnvironmentPanel environment={selectedNode} user={user} />);
|
setSidePanel(<EnvironmentPanel environment={selectedNode} />);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "share":
|
case "share":
|
||||||
setSidePanel(<SharePanel share={selectedNode} user={user} />);
|
setSidePanel(<SharePanel share={selectedNode} />);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "access":
|
case "access":
|
||||||
@ -115,7 +114,7 @@ const ApiConsole = ({ user, logout }: ApiConsoleProps) => {
|
|||||||
<NavBar logout={logout} />
|
<NavBar logout={logout} />
|
||||||
<Grid2 container spacing={2} columns={{ xs: 4, sm: 10, md: 12 }}>
|
<Grid2 container spacing={2} columns={{ xs: 4, sm: 10, md: 12 }}>
|
||||||
<Grid2 size="grow">
|
<Grid2 size="grow">
|
||||||
<Visualizer vov={overview} onSelectionChanged={setSelectedNode} />
|
<Visualizer vov={overview} onSelectionChanged={updateSelectedNode} />
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={4}>
|
<Grid2 size={4}>
|
||||||
{sidePanel}
|
{sidePanel}
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
import {BrowserRouter, Route, Routes} from "react-router";
|
import {BrowserRouter, Route, Routes} from "react-router";
|
||||||
import ApiConsole from "./ApiConsole.tsx";
|
import ApiConsole from "./ApiConsole.tsx";
|
||||||
import Login from "./Login.tsx";
|
import Login from "./Login.tsx";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect} from "react";
|
||||||
import {User} from "./model/user.ts";
|
import {User} from "./model/user.ts";
|
||||||
|
import useStore from "./model/store.ts";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [user, setUser] = useState(null as User);
|
const user = useStore((state) => state.user);
|
||||||
|
const updateUser = useStore((state) => state.updateUser);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkUser = () => {
|
const checkUser = () => {
|
||||||
const user = localStorage.getItem("user");
|
const user = localStorage.getItem("user");
|
||||||
if (user) {
|
if (user) {
|
||||||
setUser(JSON.parse(user));
|
updateUser(JSON.parse(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkUser();
|
checkUser();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const login = (user: User) => {
|
const login = (user: User) => {
|
||||||
setUser(user);
|
updateUser(user);
|
||||||
localStorage.setItem("user", JSON.stringify(user));
|
localStorage.setItem("user", JSON.stringify(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
setUser(null);
|
updateUser(null as User);
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const consoleRoot = user ? <ApiConsole user={user} logout={logout}/> : <Login onLogin={login}/>
|
const consoleRoot = user ? <ApiConsole logout={logout}/> : <Login onLogin={login}/>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import {Node} from "@xyflow/react";
|
import {Node} from "@xyflow/react";
|
||||||
import {Grid2, Typography} from "@mui/material";
|
import {Grid2, Typography} from "@mui/material";
|
||||||
import EnvironmentIcon from "@mui/icons-material/Computer";
|
import EnvironmentIcon from "@mui/icons-material/Computer";
|
||||||
import {User} from "./model/user.ts";
|
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {Configuration, Environment, MetadataApi} from "./api";
|
import {Configuration, Environment, MetadataApi} from "./api";
|
||||||
import PropertyTable from "./PropertyTable.tsx";
|
import PropertyTable from "./PropertyTable.tsx";
|
||||||
import SecretToggle from "./SecretToggle.tsx";
|
import SecretToggle from "./SecretToggle.tsx";
|
||||||
|
import useStore from "./model/store.ts";
|
||||||
|
|
||||||
interface EnvironmentPanelProps {
|
interface EnvironmentPanelProps {
|
||||||
environment: Node;
|
environment: Node;
|
||||||
user: User;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnvironmentPanel = ({ environment, user }: EnvironmentPanelProps) => {
|
const EnvironmentPanel = ({ environment }: EnvironmentPanelProps) => {
|
||||||
|
const user = useStore((state) => state.user);
|
||||||
const [detail, setDetail] = useState<Environment>(null);
|
const [detail, setDetail] = useState<Environment>(null);
|
||||||
|
|
||||||
const customProperties = {
|
const customProperties = {
|
||||||
|
@ -3,16 +3,16 @@ import {Grid2, Typography} from "@mui/material";
|
|||||||
import ShareIcon from "@mui/icons-material/Share";
|
import ShareIcon from "@mui/icons-material/Share";
|
||||||
import {Configuration, MetadataApi, Share} from "./api";
|
import {Configuration, MetadataApi, Share} from "./api";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {User} from "./model/user.ts";
|
|
||||||
import PropertyTable from "./PropertyTable.tsx";
|
import PropertyTable from "./PropertyTable.tsx";
|
||||||
import SecretToggle from "./SecretToggle.tsx";
|
import SecretToggle from "./SecretToggle.tsx";
|
||||||
|
import useStore from "./model/store.ts";
|
||||||
|
|
||||||
interface SharePanelProps {
|
interface SharePanelProps {
|
||||||
share: Node;
|
share: Node;
|
||||||
user: User;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SharePanel = ({ share, user }: SharePanelProps) => {
|
const SharePanel = ({ share }: SharePanelProps) => {
|
||||||
|
const user = useStore((state) => state.user);
|
||||||
const [detail, setDetail] = useState<Share>(null);
|
const [detail, setDetail] = useState<Share>(null);
|
||||||
|
|
||||||
const customProperties = {
|
const customProperties = {
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
import {create} from "zustand";
|
import {create} from "zustand";
|
||||||
import {Environment} from "../api";
|
import {Environment} from "../api";
|
||||||
import {VisualOverview} from "./visualizer.ts";
|
import {VisualOverview} from "./visualizer.ts";
|
||||||
|
import {Node} from "@xyflow/react";
|
||||||
|
import {User} from "./user.ts";
|
||||||
|
|
||||||
type StoreState = {
|
type StoreState = {
|
||||||
overview: VisualOverview;
|
user: User;
|
||||||
environments: Array<Environment>;
|
environments: Array<Environment>;
|
||||||
|
overview: VisualOverview;
|
||||||
|
selectedNode: Node;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StoreAction = {
|
type StoreAction = {
|
||||||
|
updateUser: (user: StoreState['user']) => void,
|
||||||
updateOverview: (vov: StoreState['overview']) => void,
|
updateOverview: (vov: StoreState['overview']) => void,
|
||||||
updateEnvironments: (environments: StoreState['environments']) => void
|
updateEnvironments: (environments: StoreState['environments']) => void,
|
||||||
|
updateSelectedNode: (selectedNode: StoreState['selectedNode']) => void
|
||||||
};
|
};
|
||||||
|
|
||||||
const useStore = create<StoreState & StoreAction>((set) => ({
|
const useStore = create<StoreState & StoreAction>((set) => ({
|
||||||
|
user: null,
|
||||||
overview: new VisualOverview(),
|
overview: new VisualOverview(),
|
||||||
environments: new Array<Environment>(),
|
environments: new Array<Environment>(),
|
||||||
|
selectedNode: null,
|
||||||
|
updateUser: (user) => set({user: user}),
|
||||||
updateOverview: (vov) => set({overview: vov}),
|
updateOverview: (vov) => set({overview: vov}),
|
||||||
updateEnvironments: (environments) => set({environments: environments}),
|
updateEnvironments: (environments) => set({environments: environments}),
|
||||||
|
updateSelectedNode: (selectedNode) => set({selectedNode: selectedNode})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useStore;
|
export default useStore;
|
||||||
|
Loading…
Reference in New Issue
Block a user