api keys
parent
cc59493b04
commit
16f3cbf1d2
|
@ -140,6 +140,10 @@
|
|||
"userProfile.column.expiresAt": "Läuft ab am",
|
||||
"userProfile.column.action": "Maßnahme",
|
||||
"userProfile.column.action.signOut": "Abmelden",
|
||||
"userProfile.column.createdAt": "Erstellt am",
|
||||
"userProfile.column.usageCount": "Anzahl der Nutzungen",
|
||||
"userProfile.column.name": "Name",
|
||||
"userProfile.column.token": "Token",
|
||||
"userProfile.changeAvatarError.notification.message": "Ihr Avatar konnte nicht geändert werden",
|
||||
"userProfile.changeAvatarError.notification.description": "Avatar muss kleiner sein als {{MAX_AVATAR_SIZE}} MB sein",
|
||||
"userProfile.form.username": "Benutzername",
|
||||
|
@ -149,6 +153,11 @@
|
|||
"userProfile.form.repeatNewPassword": "Neues Passwort wiederholen",
|
||||
"userProfile.form.language": "Sprache",
|
||||
"userProfile.header.yourSessions": "Ihre Sitzungen",
|
||||
"userProfile.header.yourApiKeys": "Ihre API Schlüssel",
|
||||
"userProfile.button.createApiKey": "Neuen API Schlüssel erstellen",
|
||||
"userProfile.button.createApiKey.popconfirm.title": "Name für den neuen API Schlüssel",
|
||||
"userProfile.button.createApiKey.popconfirm.okText": "Erstellen",
|
||||
"userProfile.button.copyToClipboard.notification": "API Token in die Zwischenablage kopiert",
|
||||
"scanners.column.name": "Name",
|
||||
"scanners.column.usedBy": "Verwendet von",
|
||||
"scanners.column.lastUsed": "Zuletzt verwendet",
|
||||
|
|
|
@ -140,6 +140,10 @@
|
|||
"userProfile.column.expiresAt": "Expires at",
|
||||
"userProfile.column.action": "Action",
|
||||
"userProfile.column.action.signOut": "Sign out",
|
||||
"userProfile.column.createdAt": "Created at",
|
||||
"userProfile.column.usageCount": "Usage count",
|
||||
"userProfile.column.name": "Name",
|
||||
"userProfile.column.token": "Token",
|
||||
"userProfile.changeAvatarError.notification.message": "Your avatar could not be changed",
|
||||
"userProfile.changeAvatarError.notification.description": "Avatar must be smaller than {{MAX_AVATAR_SIZE}} MB",
|
||||
"userProfile.form.username": "Username",
|
||||
|
@ -149,6 +153,11 @@
|
|||
"userProfile.form.repeatNewPassword": "Repeat new password",
|
||||
"userProfile.form.language": "Language",
|
||||
"userProfile.header.yourSessions": "Your sessions",
|
||||
"userProfile.header.yourApiKeys": "Your API keys",
|
||||
"userProfile.button.createApiKey": "Create new API key",
|
||||
"userProfile.button.createApiKey.popconfirm.title": "Name for the new API key",
|
||||
"userProfile.button.createApiKey.popconfirm.okText": "Create",
|
||||
"userProfile.button.copyToClipboard.notification": "API token copied to clipboard",
|
||||
"scanners.column.name": "Name",
|
||||
"scanners.column.usedBy": "Used by",
|
||||
"scanners.column.lastUsed": "Last used",
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
Col,
|
||||
Form,
|
||||
Input,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
|
@ -26,6 +27,12 @@ import {
|
|||
} from "../../utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
CopyOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
KeyOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
export default function UserProfile() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
|
@ -36,8 +43,10 @@ export default function UserProfile() {
|
|||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [repeatedNewPassword, setRepeatedNewPassword] = useState("");
|
||||
const [newApiKeyName, setNewApikeyName] = useState("");
|
||||
const [showApiKeyPassword, setShowApiKeyPassword] = useState(false);
|
||||
|
||||
const getTableColumns = () => {
|
||||
const getSessionTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: t("userProfile.column.userAgent"),
|
||||
|
@ -91,7 +100,81 @@ export default function UserProfile() {
|
|||
];
|
||||
};
|
||||
|
||||
const getTableItems = () => {
|
||||
const getApiKeyTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: t("userProfile.column.name"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
},
|
||||
{
|
||||
title: t("userProfile.column.token"),
|
||||
dataIndex: "token",
|
||||
key: "token",
|
||||
render: (text) => (
|
||||
<Space>
|
||||
{showApiKeyPassword ? text : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}
|
||||
{showApiKeyPassword ? (
|
||||
<EyeInvisibleOutlined
|
||||
onClick={() => setShowApiKeyPassword(false)}
|
||||
/>
|
||||
) : (
|
||||
<EyeOutlined onClick={() => setShowApiKeyPassword(true)} />
|
||||
)}
|
||||
{showApiKeyPassword && (
|
||||
<CopyOutlined
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(text);
|
||||
setShowApiKeyPassword(false);
|
||||
|
||||
notificationApi["info"]({
|
||||
message: t(
|
||||
"userProfile.button.copyToClipboard.notification"
|
||||
),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("userProfile.column.usageCount"),
|
||||
dataIndex: "usageCount",
|
||||
key: "usageCount",
|
||||
},
|
||||
|
||||
{
|
||||
title: t("userProfile.column.lastUsed"),
|
||||
dataIndex: "lastUsed",
|
||||
key: "lastUsed",
|
||||
},
|
||||
{
|
||||
title: t("userProfile.column.createdAt"),
|
||||
dataIndex: "createdAt",
|
||||
key: "createdAt",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const getApiKeyTableItems = () => {
|
||||
let items = [];
|
||||
|
||||
webSocketContext.User.ApiKeys.forEach((apiKey) => {
|
||||
items.push({
|
||||
key: apiKey.Id,
|
||||
name: apiKey.Name,
|
||||
token: apiKey.Token,
|
||||
usageCount: apiKey.UsageCount,
|
||||
createdAt: FormatDatetime(apiKey.CreatedAt),
|
||||
lastUsed: FormatDatetime(apiKey.LastUsed),
|
||||
});
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
const getSessionTableItems = () => {
|
||||
let items = [];
|
||||
|
||||
webSocketContext.User.Sessions.sort(
|
||||
|
@ -178,6 +261,15 @@ export default function UserProfile() {
|
|||
});
|
||||
};
|
||||
|
||||
const onCreateNewApiKeyConfirm = () => {
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.CreateNewUserApiKey,
|
||||
{ Name: newApiKeyName }
|
||||
);
|
||||
|
||||
setNewApikeyName("");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{notificationContextHolder}
|
||||
|
@ -325,7 +417,46 @@ export default function UserProfile() {
|
|||
{webSocketContext.User.Sessions.length})
|
||||
</h1>
|
||||
|
||||
<Table columns={getTableColumns()} dataSource={getTableItems()} />
|
||||
<Table
|
||||
columns={getSessionTableColumns()}
|
||||
dataSource={getSessionTableItems()}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<h1 style={{ fontWeight: "bold" }}>
|
||||
{t("userProfile.header.yourApiKeys")} (
|
||||
{webSocketContext.User.ApiKeys.length})
|
||||
</h1>
|
||||
|
||||
<Popconfirm
|
||||
placement="topRight"
|
||||
title={t("userProfile.button.createApiKey.popconfirm.title")}
|
||||
description={
|
||||
<Input
|
||||
placeholder="Name"
|
||||
value={newApiKeyName}
|
||||
onChange={(e) => setNewApikeyName(e.target.value)}
|
||||
/>
|
||||
}
|
||||
okText={t("userProfile.button.createApiKey.popconfirm.okText")}
|
||||
cancelText={t("buttonCancel")}
|
||||
onConfirm={() => onCreateNewApiKeyConfirm()}
|
||||
>
|
||||
<Button icon={<KeyOutlined />}>
|
||||
{t("userProfile.button.createApiKey")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
columns={getApiKeyTableColumns()}
|
||||
dataSource={getApiKeyTableItems()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
11
src/utils.js
11
src/utils.js
|
@ -144,6 +144,7 @@ let webSocketContextPreview = {
|
|||
Sessions: [],
|
||||
Permissions: [],
|
||||
RoleId: "",
|
||||
ApiKeys: [],
|
||||
},
|
||||
AllUsers: [],
|
||||
AllRoles: [],
|
||||
|
@ -191,6 +192,7 @@ const ReceivedMessagesCommands = {
|
|||
AllUsersUserDeleted: 27,
|
||||
AllUsersUserDeactivation: 28,
|
||||
GroupTasksCategoryGroupChanges: 29,
|
||||
NewUserApiKeyCreated: 30,
|
||||
};
|
||||
|
||||
// commands sent to the backend server
|
||||
|
@ -213,6 +215,7 @@ export const SentMessagesCommands = {
|
|||
ScannersDisconnectScanner: 16,
|
||||
GroupTasksCheckingForCategoryGroupChanges: 17,
|
||||
HandleUserActionTaskStep: 18,
|
||||
CreateNewUserApiKey: 19,
|
||||
};
|
||||
|
||||
export function WebSocketProvider({
|
||||
|
@ -951,7 +954,15 @@ export function WebSocketProvider({
|
|||
return newArr;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case ReceivedMessagesCommands.NewUserApiKeyCreated:
|
||||
setUser((user) => {
|
||||
const updatedUser = { ...user };
|
||||
|
||||
updatedUser.ApiKeys.push(body);
|
||||
|
||||
return updatedUser;
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue