diff --git a/src/frontend/src/components/OAuth2ProxyApiTokenComponent.jsx b/src/frontend/src/components/OAuth2ProxyApiTokenComponent.jsx index d3b71c6..6b22569 100644 --- a/src/frontend/src/components/OAuth2ProxyApiTokenComponent.jsx +++ b/src/frontend/src/components/OAuth2ProxyApiTokenComponent.jsx @@ -12,36 +12,71 @@ import { } from '@sonatype/nexus-ui-plugin'; export default function OAuth2ProxyApiTokenComponent() { - const [token, setToken] = React.useState(''); - const [error, setError] = React.useState(false); - - React.useEffect(() => { - (async () => { - try { - const reponse = await Axios.post("/service/rest/oauth2-proxy/user/reset-token"); - setToken(reponse.data); - } catch (e) { - setError(true); - console.error('Failed to reset token:', e); - } - })(); - }, []); - - if (error) { - return
Error fetching user data.
; - } - return -
-

A new API token has been created. It is only displayed once. Store it in a safe place!

-

⚠️ The next time you visit this page, you will automatically reset the token again.

-

💡 Make sure no one was watching when displaying this token. If in doubt, just reset it once more.

- Your API token: {token} -
+
} + +function TokenSection() { + const [token, setToken] = React.useState('****************************************'); + const [resetFailed, setResetFailed] = React.useState(false); + const [resetInProgress, setResetInProgress] = React.useState(false); + const [tokenFreshlyReset, setTokenFreshlyReset] = React.useState(false); + + const resetToken = React.useCallback(async () => { + if(resetInProgress) { + console.log("Still resetting the token, not sending another request now"); + } else { + setResetInProgress(true); + Axios.post("/service/rest/oauth2-proxy/user/reset-token") + .then(response => { + setToken(response.data); + setTokenFreshlyReset(true); + setResetInProgress(false); + }) + .catch(error => { + setResetFailed(true); + console.error('Failed to reset token:' + JSON.stringify(error.toJSON())); + setResetInProgress(false); + }); + } + }, [resetInProgress]) + + if(resetFailed) { + return
+

⛔ Failed to generate a new access token

+
+ } + + if(tokenFreshlyReset) { + return
+

✔ A new API token has been created. It is only displayed once. Store it in a safe place!

+

⚠️ The old API token has been invalidated

+

💡 Make sure no one was watching when displaying this token. If in doubt, just reset it once more.

+ resetToken()} token={token}/> +
+ } + + return
+

⚠️ Your current API token is hidden. Click the button to generate a new token

+

⚠️ When a new token is generated, the old one is invalidated immediately

+ resetToken()} token={token}/> +
+} + +function TokenFooter({resetInProgress, resetPressed, token}) { + const buttonStyle = { + marginRight: '1em', + minWidth: '10em' + } + let buttonText = resetInProgress ? "Generating..." : "Regenerate Token" + return + + Your API token: {token} + +} \ No newline at end of file diff --git a/src/frontend/src/components/OAuth2ProxyApiTokenComponent.test.jsx b/src/frontend/src/components/OAuth2ProxyApiTokenComponent.test.jsx index db1b318..b41c2e6 100644 --- a/src/frontend/src/components/OAuth2ProxyApiTokenComponent.test.jsx +++ b/src/frontend/src/components/OAuth2ProxyApiTokenComponent.test.jsx @@ -3,7 +3,7 @@ import React from 'react'; import OAuth2ProxyApiTokenComponent from './OAuth2ProxyApiTokenComponent'; import '@testing-library/jest-dom' -import { act, render } from '@testing-library/react'; +import { act, render, fireEvent } from '@testing-library/react'; jest.mock('axios'); @@ -24,9 +24,23 @@ describe('OAuth2ProxyApiTokenComponent', () => { Axios.post.mockImplementationOnce(() => Promise.resolve({ data: 'foobar' })); }); - it('calls post request once when rendered', async () => { + it('renders page without immediately re-generating the token', async () => { + const { findByText } = render(); + + const token = await findByText(/Your current API token is hidden/i); + expect(token).toBeInTheDocument(); + + const button = await findByText(/Regenerate Token/i); + expect(button).toBeInTheDocument(); + + expect(Axios.post).toHaveBeenCalledTimes(0); + }); + + it('calls post request once when regenerate button is clicked', async () => { await act(async () => { - render(); + const { findByText } = render(); + const button = await findByText(/Regenerate Token/i); + fireEvent.click(button); }); expect(Axios.post).toHaveBeenCalledTimes(1); @@ -34,9 +48,13 @@ describe('OAuth2ProxyApiTokenComponent', () => { }); it('renders response content as token', async () => { - const { findByText } = render(); - - const token = await findByText(/foobar/i); - expect(token).toBeInTheDocument(); + await act(async () => { + const { findByText } = render(); + const button = await findByText(/Regenerate Token/i); + fireEvent.click(button); + + const token = await findByText(/foobar/i); + expect(token).toBeInTheDocument(); + }); }); }); \ No newline at end of file