Skip to content

Commit

Permalink
Improve style and API flow
Browse files Browse the repository at this point in the history
Signed-off-by: Olivier Léobal <[email protected]>
  • Loading branch information
oleobal committed Mar 28, 2023
1 parent 94761d9 commit 5efbd86
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 89 deletions.
1 change: 1 addition & 0 deletions src/assets/chakraTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export default extendTheme({
baseStyle: {
...noBorderRadius,
fontFamily: 'Gattica',
_hover: { textDecoration: 'none' },
},
},
CloseButton: noDefaultBorderRadius,
Expand Down
74 changes: 38 additions & 36 deletions src/components/ApiToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import {
} from '@chakra-ui/react';

import { useToast } from '@/hooks/useToast';
import { requestToken } from '@/modules/bearerTokens/BearerTokenApi';
import {
BearerTokenT,
NewBearerTokenT,
} from '@/modules/bearerTokens/BearerTokenTypes';
import { requestToken } from '@/modules/bearerTokens/BearerTokenUtils';
import { parseNewToken } from '@/modules/bearerTokens/BearerTokenUtils';

import CopyButton from './CopyButton';

Expand All @@ -27,55 +28,56 @@ const ApiToken = ({ token }: { token: BearerTokenT | NewBearerTokenT }) => {
);
const toast = useToast();

const getNewToken = () => {
requestToken()
.then((response) => {
setApiToken(response);
toast({
title: 'Token regenerated',
description: 'The old token is no longer valid.',
status: 'success',
isClosable: true,
});
})
.catch((error) => {
console.error(error);
toast({
title: "Couldn't get a new token",
description: 'Something went wrong',
status: 'error',
isClosable: true,
});
const getNewToken = async () => {
try {
const response = await requestToken();
setApiToken(parseNewToken(response.data));
toast({
title: 'Token regenerated',
descriptionComponent: 'The old token is no longer valid.',
status: 'success',
isClosable: true,
});
} catch (error) {
console.error(error);
toast({
title: "Couldn't get a new token",
status: 'error',
isClosable: true,
});
}
};

const tokenIsExpired = apiToken.expires_at < new Date();

return (
<Box border="1px" borderColor="gray.200" padding="10px">
<Box
borderWidth="1px"
borderStyle="solid"
borderColor="gray.100"
padding="2.5"
>
<HStack>
<VStack align="left">
<Text fontSize="sm">
{'Created ' + apiToken.created_at.toLocaleString()}
{`Created ${apiToken.created_at.toLocaleString()}`}
</Text>
<Text
fontSize="sm"
color={tokenIsExpired ? 'red.500' : undefined}
>
{'Expires ' + apiToken.expires_at.toLocaleString()}
{`Expires ${apiToken.expires_at.toLocaleString()}`}
</Text>
<HStack height="35px">
{'token' in apiToken ? (
<>
<Code width="300px">{apiToken.token}</Code>
<CopyButton value={apiToken.token} />
</>
) : (
<Text fontSize="sm" as="i">
Generated tokens are only displayed once.
</Text>
)}
</HStack>
{'token' in apiToken ? (
<HStack height="35px">
<Code width="300px">{apiToken.token}</Code>
<CopyButton value={apiToken.token} />
</HStack>
) : (
<Text height="35px" fontSize="sm" fontStyle="italic">
Generated tokens are only displayed once.
</Text>
)}
</VStack>
<Spacer />
<Center width="120px">
Expand All @@ -87,7 +89,7 @@ const ApiToken = ({ token }: { token: BearerTokenT | NewBearerTokenT }) => {
>
<Button
onClick={getNewToken}
disabled={'token' in apiToken}
isDisabled={'token' in apiToken}
>
Regenerate
</Button>
Expand Down
45 changes: 23 additions & 22 deletions src/components/layout/header/ApiTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ import {
} from '@chakra-ui/react';

import { useToast } from '@/hooks/useToast';
import { BearerTokenT } from '@/modules/bearerTokens/BearerTokenTypes';
import {
listActiveTokens,
requestToken,
} from '@/modules/bearerTokens/BearerTokenApi';
import { BearerTokenT } from '@/modules/bearerTokens/BearerTokenTypes';
import {
parseToken,
parseNewToken,
} from '@/modules/bearerTokens/BearerTokenUtils';

import ApiToken from '@/components/ApiToken';
Expand All @@ -31,30 +35,27 @@ const ApiTokens = () => {
const [activeTokens, setActiveTokens] = useState<BearerTokenT[]>([]);
const toast = useToast();

const getFirstToken = () => {
requestToken()
.then((response) => {
setActiveTokens([response]);
})
.catch((error) => {
console.error(error);
toast({
title: "Couldn't get a new token",
description: 'Something went wrong',
status: 'error',
isClosable: true,
});
const getFirstToken = async () => {
try {
const response = await requestToken();
setActiveTokens([parseNewToken(response.data)]);
} catch (error) {
console.error(error);
toast({
title: "Couldn't get a new token",
status: 'error',
isClosable: true,
});
}
};

const getActiveTokens = () => {
listActiveTokens()
.then((response) => {
setActiveTokens(response);
})
.catch((error) => {
console.error(error);
});
const getActiveTokens = async () => {
try {
const response = await listActiveTokens();
setActiveTokens(response.data.tokens.map(parseToken));
} catch (error) {
console.error(error);
}
};

useEffect(() => {
Expand Down
10 changes: 8 additions & 2 deletions src/modules/bearerTokens/BearerTokenApi.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { AxiosResponse } from 'axios';

import API from '@/libs/request';

import { RawBearerTokenT, RawNewBearerTokenT } from './BearerTokenTypes';

const URLS = {
API_TOKEN: `/api-token`,
ACTIVE_API_TOKENS: `/active-api-tokens`,
};

export const requestToken = () => {
export const requestToken = (): Promise<AxiosResponse<RawNewBearerTokenT>> => {
return API.authenticatedGet(URLS.API_TOKEN);
};

export const listActiveTokens = () => {
export const listActiveTokens = (): Promise<
AxiosResponse<{ tokens: RawBearerTokenT[] }>
> => {
return API.authenticatedGet(URLS.ACTIVE_API_TOKENS);
};
20 changes: 2 additions & 18 deletions src/modules/bearerTokens/BearerTokenUtils.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,21 @@
import {
listActiveTokens as listActiveTokensFromApi,
requestToken as requestTokensFromApi,
} from './BearerTokenApi';
import {
BearerTokenT,
NewBearerTokenT,
RawBearerTokenT,
RawNewBearerTokenT,
} from './BearerTokenTypes';

const parseToken = (object: RawBearerTokenT): BearerTokenT => {
export const parseToken = (object: RawBearerTokenT): BearerTokenT => {
return {
created_at: new Date(object.created_at),
expires_at: new Date(object.expires_at),
};
};

const parseNewToken = (object: RawNewBearerTokenT): NewBearerTokenT => {
export const parseNewToken = (object: RawNewBearerTokenT): NewBearerTokenT => {
return {
token: object.token,
created_at: new Date(object.created_at),
expires_at: new Date(object.expires_at),
};
};

export const requestToken = (): Promise<NewBearerTokenT> => {
return requestTokensFromApi().then((response) => {
return parseNewToken(response.data);
});
};

export const listActiveTokens = (): Promise<BearerTokenT[]> => {
return listActiveTokensFromApi().then((response) => {
return (response.data.tokens as RawBearerTokenT[]).map(parseToken);
});
};
22 changes: 11 additions & 11 deletions src/routes/login/components/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,18 @@ const LoginForm = (): JSX.Element => {

{authInfo?.oidc && (
<Box>
<Link
href={
`${API_URL}${authInfo.oidc.login_url}?next=` +
encodeURIComponent(
window.location.origin + nextLocation
)
}
<Button
width="100%"
marginBottom="4"
as={Link}
href={`${API_URL}${
authInfo.oidc.login_url
}?next=${encodeURIComponent(
window.location.origin + nextLocation
)}`}
>
<Button width="100%" marginBottom="4">
Sign in with {authInfo.oidc.name}
</Button>
</Link>
Sign in with {authInfo.oidc.name}
</Button>
<Divider marginBottom="4" />
</Box>
)}
Expand Down

0 comments on commit 5efbd86

Please sign in to comment.