Add token creation dialog
This commit is contained in:
159
matrixgw_frontend/src/dialogs/CreateTokenDialog.tsx
Normal file
159
matrixgw_frontend/src/dialogs/CreateTokenDialog.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { ServerApi } from "../api/ServerApi";
|
||||
import {
|
||||
TokensApi,
|
||||
type BaseToken,
|
||||
type TokenWithSecret,
|
||||
} from "../api/TokensApi";
|
||||
import { useAlert } from "../hooks/contexts_provider/AlertDialogProvider";
|
||||
import { useLoadingMessage } from "../hooks/contexts_provider/LoadingMessageProvider";
|
||||
import { time } from "../utils/DateUtils";
|
||||
import {
|
||||
checkConstraint,
|
||||
checkNumberConstraint,
|
||||
isIPNetworkValid,
|
||||
} from "../utils/FormUtils";
|
||||
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
|
||||
import { DateInput } from "../widgets/forms/DateInput";
|
||||
import { NetworksInput } from "../widgets/forms/NetworksInput";
|
||||
import { TextInput } from "../widgets/forms/TextInput";
|
||||
|
||||
const SECS_IN_DAY = 3600 * 24;
|
||||
|
||||
export function CreateTokenDialog(p: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onCreated: (t: TokenWithSecret) => void;
|
||||
}): React.ReactElement {
|
||||
const alert = useAlert();
|
||||
const loadingMessage = useLoadingMessage();
|
||||
|
||||
const [newTokenUndef, setNewToken] = React.useState<BaseToken | undefined>();
|
||||
const newToken: BaseToken = newTokenUndef ?? {
|
||||
name: "",
|
||||
max_inactivity: 3600 * 24 * 90,
|
||||
read_only: false,
|
||||
};
|
||||
|
||||
const valid =
|
||||
checkConstraint(ServerApi.Config.constraints.token_name, newToken.name) ===
|
||||
undefined &&
|
||||
checkNumberConstraint(
|
||||
ServerApi.Config.constraints.token_max_inactivity,
|
||||
newToken.max_inactivity
|
||||
) === undefined &&
|
||||
(newToken.networks === undefined ||
|
||||
newToken.networks.every((n) => isIPNetworkValid(n)));
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
loadingMessage.show("Creating access token...");
|
||||
const token = await TokensApi.Create(newToken);
|
||||
p.onCreated(token);
|
||||
|
||||
// Clear form
|
||||
setNewToken(undefined);
|
||||
} catch (e) {
|
||||
console.error(`Failed to create token! ${e}`);
|
||||
alert(`Failed to create API token! ${e}`);
|
||||
} finally {
|
||||
loadingMessage.hide();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={p.open} onClose={p.onClose}>
|
||||
<DialogTitle>Create new API token</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextInput
|
||||
editable
|
||||
required
|
||||
label="Token name"
|
||||
value={newToken.name}
|
||||
onValueChange={(v) => {
|
||||
setNewToken({
|
||||
...newToken,
|
||||
name: v ?? "",
|
||||
});
|
||||
}}
|
||||
size={ServerApi.Config.constraints.token_name}
|
||||
/>
|
||||
|
||||
<NetworksInput
|
||||
editable
|
||||
label="Allowed networks (CIDR notation)"
|
||||
value={newToken.networks}
|
||||
onChange={(v) => {
|
||||
setNewToken({
|
||||
...newToken,
|
||||
networks: v,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
editable
|
||||
required
|
||||
label="Max inactivity period (days)"
|
||||
type="number"
|
||||
value={(newToken.max_inactivity / SECS_IN_DAY).toString()}
|
||||
onValueChange={(i) => {
|
||||
setNewToken({
|
||||
...newToken,
|
||||
max_inactivity: Number(i) * SECS_IN_DAY,
|
||||
});
|
||||
}}
|
||||
size={{
|
||||
min:
|
||||
ServerApi.Config.constraints.token_max_inactivity.min /
|
||||
SECS_IN_DAY,
|
||||
max:
|
||||
ServerApi.Config.constraints.token_max_inactivity.max /
|
||||
SECS_IN_DAY,
|
||||
}}
|
||||
/>
|
||||
|
||||
<DateInput
|
||||
editable
|
||||
label="Expiration date (optional)"
|
||||
value={newToken.expiration}
|
||||
onChange={(i) => {
|
||||
setNewToken((t) => {
|
||||
return {
|
||||
...(t ?? newToken),
|
||||
expiration: i ?? undefined,
|
||||
};
|
||||
});
|
||||
}}
|
||||
disablePast
|
||||
checkValue={(s) => s > time()}
|
||||
/>
|
||||
|
||||
<CheckboxInput
|
||||
editable
|
||||
label="Read only"
|
||||
checked={newToken.read_only}
|
||||
onValueChange={(v) => {
|
||||
setNewToken({
|
||||
...newToken,
|
||||
read_only: v,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={p.onClose}>Cancel</Button>
|
||||
<Button onClick={handleSubmit} disabled={!valid} autoFocus>
|
||||
Create token
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user