kopia lustrzana https://github.com/bugout-dev/moonstream
commit
98ab736ef4
|
@ -4,6 +4,8 @@ import TokenRequest from "../../src/components/TokenRequest";
|
||||||
import { useTokens } from "../../src/core/hooks";
|
import { useTokens } from "../../src/core/hooks";
|
||||||
import {
|
import {
|
||||||
VStack,
|
VStack,
|
||||||
|
Stack,
|
||||||
|
Input,
|
||||||
Box,
|
Box,
|
||||||
Center,
|
Center,
|
||||||
Spinner,
|
Spinner,
|
||||||
|
@ -17,12 +19,14 @@ import {
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalBody,
|
ModalBody,
|
||||||
ModalCloseButton,
|
ModalCloseButton,
|
||||||
|
InputGroup,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { getLayout } from "../../src/layouts/AccountLayout";
|
import { getLayout } from "../../src/layouts/AccountLayout";
|
||||||
|
|
||||||
const Tokens = () => {
|
const Tokens = () => {
|
||||||
const { onOpen, onClose, isOpen } = useDisclosure();
|
const { onOpen, onClose, isOpen } = useDisclosure();
|
||||||
const [newToken, setNewToken] = useState(null);
|
const [newToken, setNewToken] = useState(null);
|
||||||
|
const [filter, setFilter] = useState("");
|
||||||
const [tokens, setTokens] = useState();
|
const [tokens, setTokens] = useState();
|
||||||
const { list, updateMutation, revoke, isLoading, data } = useTokens();
|
const { list, updateMutation, revoke, isLoading, data } = useTokens();
|
||||||
|
|
||||||
|
@ -50,6 +54,7 @@ const Tokens = () => {
|
||||||
document.title = `Tokens`;
|
document.title = `Tokens`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleChange = (event) => setFilter(event.target.value);
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{isLoading && !tokens ? (
|
{isLoading && !tokens ? (
|
||||||
|
@ -77,17 +82,36 @@ const Tokens = () => {
|
||||||
</Modal>
|
</Modal>
|
||||||
<Heading variant="tokensScreen"> My API tokens </Heading>
|
<Heading variant="tokensScreen"> My API tokens </Heading>
|
||||||
<VStack overflow="initial" maxH="unset" height="100%" maxW="100%">
|
<VStack overflow="initial" maxH="unset" height="100%" maxW="100%">
|
||||||
<Button
|
<Stack direction={["column", "row", null]} w="100%">
|
||||||
alignSelf="flex-end"
|
<InputGroup size="sm" variant="outline">
|
||||||
onClick={onOpen}
|
<Input
|
||||||
colorScheme="orange"
|
type="search"
|
||||||
variant="solid"
|
maxW="300px"
|
||||||
size="sm"
|
flexBasis="50px"
|
||||||
>
|
flexGrow={1}
|
||||||
Add new token
|
display="flex"
|
||||||
</Button>
|
minW="150px"
|
||||||
|
w="unset"
|
||||||
|
borderRadius="md"
|
||||||
|
placeholder="Type here to filter by label name"
|
||||||
|
value={filter}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</InputGroup>
|
||||||
|
<Button
|
||||||
|
alignSelf="flex-end"
|
||||||
|
onClick={onOpen}
|
||||||
|
colorScheme="orange"
|
||||||
|
variant="solid"
|
||||||
|
px="2rem"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
Add new token
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
<TokensList
|
<TokensList
|
||||||
data={tokens}
|
data={tokens}
|
||||||
|
filter={filter}
|
||||||
revoke={revoke}
|
revoke={revoke}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
update={updateMutation}
|
update={updateMutation}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect, useState, useMemo } from "react";
|
||||||
import { Skeleton, IconButton } from "@chakra-ui/react";
|
import { Skeleton, IconButton } from "@chakra-ui/react";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
@ -9,19 +9,77 @@ import {
|
||||||
Tbody,
|
Tbody,
|
||||||
Editable,
|
Editable,
|
||||||
EditableInput,
|
EditableInput,
|
||||||
|
Button,
|
||||||
EditablePreview,
|
EditablePreview,
|
||||||
|
useBreakpointValue,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { DeleteIcon } from "@chakra-ui/icons";
|
import { DeleteIcon, TriangleDownIcon } from "@chakra-ui/icons";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import CopyButton from "./CopyButton";
|
import CopyButton from "./CopyButton";
|
||||||
|
|
||||||
const List = ({ data, revoke, isLoading, update }) => {
|
const SORT_BY_TYPES = {
|
||||||
|
DATE: 0,
|
||||||
|
LABEL: 1,
|
||||||
|
};
|
||||||
|
const SORT_DIRECTION_TYPES = {
|
||||||
|
ASC: true,
|
||||||
|
DESC: false,
|
||||||
|
};
|
||||||
|
const List = ({ data, revoke, isLoading, update, filter }) => {
|
||||||
|
const [stateData, setStateData] = useState(data);
|
||||||
const userToken = localStorage.getItem("MOONSTREAM_ACCESS_TOKEN");
|
const userToken = localStorage.getItem("MOONSTREAM_ACCESS_TOKEN");
|
||||||
|
const [sortBy, setSortBy] = useState({
|
||||||
|
column: SORT_BY_TYPES.LABEL,
|
||||||
|
direction: SORT_DIRECTION_TYPES.ASC,
|
||||||
|
});
|
||||||
|
|
||||||
|
const buttonSize = useBreakpointValue({
|
||||||
|
base: "xs",
|
||||||
|
sm: "sm",
|
||||||
|
md: "sm",
|
||||||
|
lg: "sm",
|
||||||
|
xl: "sm",
|
||||||
|
"2xl": "sm",
|
||||||
|
});
|
||||||
|
|
||||||
|
const sortedTokens = useMemo(() => {
|
||||||
|
return data?.token?.sort(function (a, b) {
|
||||||
|
var aName = a?.note?.toUpperCase();
|
||||||
|
var bName = b?.note?.toUpperCase();
|
||||||
|
|
||||||
|
if ((a.note || b.note) && sortBy.column === SORT_BY_TYPES.LABEL) {
|
||||||
|
if (!b.note) return -1;
|
||||||
|
if (sortBy.direction === SORT_DIRECTION_TYPES.ASC) {
|
||||||
|
return aName < bName ? -1 : aName > bName ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
return aName > bName ? -1 : aName < bName ? 1 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sortBy.direction === SORT_DIRECTION_TYPES.ASC) {
|
||||||
|
return new Date(b.created_at) - new Date(a.created_at);
|
||||||
|
} else {
|
||||||
|
return new Date(a.created_at) - new Date(b.created_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [sortBy, data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data?.token?.length > 0) {
|
||||||
|
const filteredTokens = sortedTokens.filter((item) => {
|
||||||
|
if (filter === null || filter === undefined || filter === "") {
|
||||||
|
return true;
|
||||||
|
} else return item.note.includes(filter);
|
||||||
|
});
|
||||||
|
|
||||||
|
setStateData({ ...data, token: [...filteredTokens] });
|
||||||
|
}
|
||||||
|
}, [data, sortBy, filter, sortedTokens]);
|
||||||
|
|
||||||
const cellProps = {
|
const cellProps = {
|
||||||
px: ["2px", "6px", "inherit"],
|
px: ["2px", "6px", "inherit"],
|
||||||
};
|
};
|
||||||
if (data) {
|
if (stateData) {
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
variant="simple"
|
variant="simple"
|
||||||
|
@ -33,14 +91,86 @@ const List = ({ data, revoke, isLoading, update }) => {
|
||||||
>
|
>
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Label</Th>
|
<Th>
|
||||||
<Th {...cellProps}>Token</Th>
|
<Button
|
||||||
<Th {...cellProps}>Date Created</Th>
|
variant="link"
|
||||||
<Th {...cellProps}>Actions</Th>
|
my={0}
|
||||||
|
mx={0}
|
||||||
|
size={buttonSize}
|
||||||
|
colorScheme={
|
||||||
|
sortBy.column !== SORT_BY_TYPES.LABEL ? "blue" : "orange"
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
setSortBy({
|
||||||
|
column: SORT_BY_TYPES.LABEL,
|
||||||
|
direction:
|
||||||
|
sortBy.column !== SORT_BY_TYPES.LABEL
|
||||||
|
? SORT_DIRECTION_TYPES.ASC
|
||||||
|
: !sortBy.direction,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rightIcon={
|
||||||
|
<TriangleDownIcon
|
||||||
|
color={
|
||||||
|
sortBy.column !== SORT_BY_TYPES.LABEL && "transparent"
|
||||||
|
}
|
||||||
|
boxSize="12px"
|
||||||
|
transform={
|
||||||
|
sortBy.direction === SORT_DIRECTION_TYPES.ASC
|
||||||
|
? "rotate(0deg)"
|
||||||
|
: "rotate(180deg)"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Label
|
||||||
|
</Button>
|
||||||
|
</Th>
|
||||||
|
<Th {...cellProps} fontSize={["xx-small", "xs", null]}>
|
||||||
|
Token
|
||||||
|
</Th>
|
||||||
|
<Th {...cellProps} fontSize={["xx-small", "xs", null]}>
|
||||||
|
<Button
|
||||||
|
mx={0}
|
||||||
|
variant="link"
|
||||||
|
my={0}
|
||||||
|
size={buttonSize}
|
||||||
|
colorScheme={
|
||||||
|
sortBy.column !== SORT_BY_TYPES.DATE ? "blue" : "orange"
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
setSortBy({
|
||||||
|
column: SORT_BY_TYPES.DATE,
|
||||||
|
direction:
|
||||||
|
sortBy.column !== SORT_BY_TYPES.DATE
|
||||||
|
? SORT_DIRECTION_TYPES.ASC
|
||||||
|
: !sortBy.direction,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
rightIcon={
|
||||||
|
<TriangleDownIcon
|
||||||
|
color={
|
||||||
|
sortBy.column !== SORT_BY_TYPES.DATE && "transparent"
|
||||||
|
}
|
||||||
|
boxSize="12px"
|
||||||
|
transform={
|
||||||
|
sortBy.direction === SORT_DIRECTION_TYPES.ASC
|
||||||
|
? "rotate(0deg)"
|
||||||
|
: "rotate(180deg)"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{`Date Created`}
|
||||||
|
</Button>
|
||||||
|
</Th>
|
||||||
|
<Th {...cellProps} fontSize={["xx-small", "xs", null]}>
|
||||||
|
Actions
|
||||||
|
</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{data.token.map((token) => {
|
{stateData.token?.map((token) => {
|
||||||
if (token.active) {
|
if (token.active) {
|
||||||
if (userToken !== token.id) {
|
if (userToken !== token.id) {
|
||||||
return (
|
return (
|
||||||
|
@ -50,7 +180,6 @@ const List = ({ data, revoke, isLoading, update }) => {
|
||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
placeholder="Click to set up label"
|
placeholder="Click to set up label"
|
||||||
defaultValue={token.note}
|
defaultValue={token.note}
|
||||||
isDisabled={update.isLoading}
|
|
||||||
onSubmit={(nextValue) =>
|
onSubmit={(nextValue) =>
|
||||||
update.mutate({ token: token.id, note: nextValue })
|
update.mutate({ token: token.id, note: nextValue })
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue