more state store, less random property wiring (#724)

This commit is contained in:
Michael Quigley 2024-12-20 10:43:30 -05:00
parent db85823151
commit 544c1757f5
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
6 changed files with 40 additions and 28 deletions

View File

@ -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} />
} }

View File

@ -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}

View File

@ -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>

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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;