mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-17 20:45:44 +00:00
[FR] Add Tokens to PUI (#7693)
* [FR] Add Tokens to PUI Fixes #6500 * fix name / call pattern * cleanup * add "revoke" action * Lock currently used token * Update serializers.py * bump api version
This commit is contained in:
@ -14,6 +14,7 @@ export enum ApiEndpoints {
|
||||
user_me = 'user/me/',
|
||||
user_roles = 'user/roles/',
|
||||
user_token = 'user/token/',
|
||||
user_tokens = 'user/tokens/',
|
||||
user_simple_login = 'email/generate/',
|
||||
user_reset = 'auth/password/reset/',
|
||||
user_reset_set = 'auth/password/reset/confirm/',
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
Loader,
|
||||
Radio,
|
||||
Stack,
|
||||
Table,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
@ -15,9 +16,10 @@ import {
|
||||
} from '@mantine/core';
|
||||
import { IconAlertCircle, IconAt } from '@tabler/icons-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { api, queryClient } from '../../../../App';
|
||||
import { YesNoButton } from '../../../../components/buttons/YesNoButton';
|
||||
import { PlaceholderPill } from '../../../../components/items/Placeholder';
|
||||
import { ApiEndpoints } from '../../../../enums/ApiEndpoints';
|
||||
import { apiUrl } from '../../../../states/ApiState';
|
||||
@ -85,6 +87,11 @@ export function SecurityContent() {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Title order={5}>
|
||||
<Trans>Token</Trans>
|
||||
</Title>
|
||||
<TokenContent />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@ -329,3 +336,85 @@ function MfaContent() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function TokenContent() {
|
||||
const { isLoading, data, refetch } = useQuery({
|
||||
queryKey: ['token-list'],
|
||||
queryFn: () =>
|
||||
api.get(apiUrl(ApiEndpoints.user_tokens)).then((res) => res.data)
|
||||
});
|
||||
|
||||
function revokeToken(id: string) {
|
||||
api
|
||||
.delete(apiUrl(ApiEndpoints.user_tokens, id))
|
||||
.then(() => {
|
||||
refetch();
|
||||
})
|
||||
.catch((res) => console.log(res.data));
|
||||
}
|
||||
const rows = useMemo(() => {
|
||||
if (isLoading || data === undefined) return null;
|
||||
return data.map((token: any) => (
|
||||
<Table.Tr key={token.id}>
|
||||
<Table.Td>
|
||||
<YesNoButton value={token.active} />
|
||||
</Table.Td>
|
||||
<Table.Td>{token.expiry}</Table.Td>
|
||||
<Table.Td>{token.last_seen}</Table.Td>
|
||||
<Table.Td>{token.token}</Table.Td>
|
||||
<Table.Td>{token.name}</Table.Td>
|
||||
<Table.Td>
|
||||
{token.in_use ? (
|
||||
<Trans>Token is used - no actions</Trans>
|
||||
) : (
|
||||
<Button
|
||||
onClick={() => revokeToken(token.id)}
|
||||
color="red"
|
||||
disabled={!token.active}
|
||||
>
|
||||
<Trans>Revoke</Trans>
|
||||
</Button>
|
||||
)}
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
));
|
||||
}, [data, isLoading]);
|
||||
|
||||
/* renderer */
|
||||
if (isLoading) return <Loader />;
|
||||
|
||||
if (data.length == 0)
|
||||
return (
|
||||
<Alert icon={<IconAlertCircle size="1rem" />} color="green">
|
||||
<Trans>No tokens configured</Trans>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
return (
|
||||
<Table stickyHeader striped highlightOnHover withTableBorder>
|
||||
<Table.Thead>
|
||||
<Table.Tr>
|
||||
<Table.Th>
|
||||
<Trans>Active</Trans>
|
||||
</Table.Th>
|
||||
<Table.Th>
|
||||
<Trans>Expiry</Trans>
|
||||
</Table.Th>
|
||||
<Table.Th>
|
||||
<Trans>Last Seen</Trans>
|
||||
</Table.Th>
|
||||
<Table.Th>
|
||||
<Trans>Token</Trans>
|
||||
</Table.Th>
|
||||
<Table.Th>
|
||||
<Trans>Name</Trans>
|
||||
</Table.Th>
|
||||
<Table.Th>
|
||||
<Trans>Actions</Trans>
|
||||
</Table.Th>
|
||||
</Table.Tr>
|
||||
</Table.Thead>
|
||||
<Table.Tbody>{rows}</Table.Tbody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user