Add API tokens support #9
@ -2,6 +2,11 @@ import {
|
|||||||
Checkbox,
|
Checkbox,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Paper,
|
Paper,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
@ -22,6 +27,215 @@ export function TokenRightsEditor(p: {
|
|||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* Virtual machines */}
|
||||||
|
<RightsSection label="Virtual machines">
|
||||||
|
<RouteRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "POST", path: "/api/vm/create" }}
|
||||||
|
label="Create a new virtual machine"
|
||||||
|
/>
|
||||||
|
<RouteRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/list" }}
|
||||||
|
label="Get list of virtual machines"
|
||||||
|
/>
|
||||||
|
<RouteRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vnc" }}
|
||||||
|
label="Establish VNC connection"
|
||||||
|
/>
|
||||||
|
</RightsSection>
|
||||||
|
|
||||||
|
<RightsSection label="VM configuration management">
|
||||||
|
<Table size="small">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>VM name</TableCell>
|
||||||
|
<TableCell>Get definition</TableCell>
|
||||||
|
<TableCell>Update</TableCell>
|
||||||
|
<TableCell>Delete</TableCell>
|
||||||
|
<TableCell>Get XML definition</TableCell>
|
||||||
|
<TableCell>Get autostart</TableCell>
|
||||||
|
<TableCell>Set autostart</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{/* All VM operations */}
|
||||||
|
<TableRow hover>
|
||||||
|
<TableCell>
|
||||||
|
<i>All</i>
|
||||||
|
</TableCell>
|
||||||
|
<CellRight {...p} right={{ verb: "GET", path: "/api/vm/*" }} />
|
||||||
|
<CellRight {...p} right={{ verb: "PUT", path: "/api/vm/*" }} />
|
||||||
|
<CellRight {...p} right={{ verb: "DELETE", path: "/api/vm/*" }} />
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/src" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/autostart" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "PUT", path: "/api/vm/*/autostart" }}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
{/* Per VM operations */}
|
||||||
|
{p.vms.map((v, n) => (
|
||||||
|
<TableRow hover key={n}>
|
||||||
|
<TableCell>{v.name}</TableCell>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "PUT", path: `/api/vm/${v.uuid}` }}
|
||||||
|
parent={{ verb: "PUT", path: "/api/vm/*" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "DELETE", path: `/api/vm/${v.uuid}` }}
|
||||||
|
parent={{ verb: "DELETE", path: "/api/vm/*" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/src` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/src" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/autostart` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/autostart" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "PUT", path: `/api/vm/${v.uuid}/autostart` }}
|
||||||
|
parent={{ verb: "PUT", path: "/api/vm/*/autostart" }}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</RightsSection>
|
||||||
|
|
||||||
|
<RightsSection label="VM maintenance">
|
||||||
|
<Table size="small">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>VM name</TableCell>
|
||||||
|
<TableCell>Get state</TableCell>
|
||||||
|
<TableCell>Start</TableCell>
|
||||||
|
<TableCell>Shutdown</TableCell>
|
||||||
|
<TableCell>Kill</TableCell>
|
||||||
|
<TableCell>Reset</TableCell>
|
||||||
|
<TableCell>Suspend</TableCell>
|
||||||
|
<TableCell>Resume</TableCell>
|
||||||
|
<TableCell>Screenshot</TableCell>
|
||||||
|
<TableCell>VNC token</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{/* All VM operations */}
|
||||||
|
<TableRow hover>
|
||||||
|
<TableCell>
|
||||||
|
<i>All</i>
|
||||||
|
</TableCell>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/state" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/start" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/shutdown" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/kill" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/reset" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/suspend" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/resume" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/screenshot" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: "/api/vm/*/vnc" }}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
{/* Per VM operations */}
|
||||||
|
{p.vms.map((v, n) => (
|
||||||
|
<TableRow hover key={n}>
|
||||||
|
<TableCell>{v.name}</TableCell>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/state` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/state" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/start` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/start" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/shutdown` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/shutdown" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/kill` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/kill" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/reset` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/reset" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/suspend` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/suspend" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/resume` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/resume" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/screenshot` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/screenshot" }}
|
||||||
|
/>
|
||||||
|
<CellRight
|
||||||
|
{...p}
|
||||||
|
right={{ verb: "GET", path: `/api/vm/${v.uuid}/vnc` }}
|
||||||
|
parent={{ verb: "GET", path: "/api/vm/*/vnc" }}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</RightsSection>
|
||||||
{/* ISO files */}
|
{/* ISO files */}
|
||||||
<RightsSection label="ISO files">
|
<RightsSection label="ISO files">
|
||||||
<RouteRight
|
<RouteRight
|
||||||
@ -87,31 +301,47 @@ function RightsSection(
|
|||||||
p: React.PropsWithChildren<{ label: string }>
|
p: React.PropsWithChildren<{ label: string }>
|
||||||
): React.ReactElement {
|
): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<Paper style={{ padding: "20px" }}>
|
<Paper style={{ padding: "20px", margin: "10px" }}>
|
||||||
<Typography variant="h5">{p.label}</Typography>
|
<Typography variant="h5">{p.label}</Typography>
|
||||||
{p.children}
|
{p.children}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RouteRight(p: {
|
interface RightOpts {
|
||||||
right: TokenRight;
|
right: TokenRight;
|
||||||
label?: string;
|
label?: string;
|
||||||
editable: boolean;
|
editable: boolean;
|
||||||
token: APIToken;
|
token: APIToken;
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
parent?: TokenRight;
|
parent?: TokenRight;
|
||||||
}): React.ReactElement {
|
}
|
||||||
const activated =
|
|
||||||
p.token.rights.find(
|
function CellRight(p: RightOpts): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<TableCell align="center">
|
||||||
|
<RouteRight {...p} />
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RouteRight(p: RightOpts): React.ReactElement {
|
||||||
|
const rightIndex = p.token.rights.findIndex(
|
||||||
(r) => r.verb === p.right.verb && r.path === p.right.path
|
(r) => r.verb === p.right.verb && r.path === p.right.path
|
||||||
) !== undefined;
|
);
|
||||||
|
const activated = rightIndex !== -1;
|
||||||
|
|
||||||
|
const parentActivated =
|
||||||
|
!!p.parent &&
|
||||||
|
p.token.rights.findIndex(
|
||||||
|
(r) => r.verb === p.parent?.verb && r.path === p.parent?.path
|
||||||
|
) !== -1;
|
||||||
|
|
||||||
const toggle = (a: boolean) => {
|
const toggle = (a: boolean) => {
|
||||||
if (a) {
|
if (a) {
|
||||||
p.token.rights.push(p.right);
|
p.token.rights.push(p.right);
|
||||||
} else {
|
} else {
|
||||||
p.token.rights.splice(p.token.rights.indexOf(p.right), 1);
|
p.token.rights.splice(rightIndex, 1);
|
||||||
}
|
}
|
||||||
p.onChange?.();
|
p.onChange?.();
|
||||||
};
|
};
|
||||||
@ -138,8 +368,8 @@ function RouteRight(p: {
|
|||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={activated}
|
checked={activated || parentActivated}
|
||||||
disabled={!p.editable}
|
disabled={!p.editable || parentActivated}
|
||||||
onChange={(_e, a) => toggle(a)}
|
onChange={(_e, a) => toggle(a)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user