Skip to content

Commit

Permalink
fix: explain api maintenance mode (#1545)
Browse files Browse the repository at this point in the history
* feat: add error handling to token context

* feat: refine error messaging for token api errors

* feat: add error messaging to token creator

* feat: add error messaging to token manager
  • Loading branch information
johnathonroach committed Jun 24, 2022
1 parent 044cff8 commit cabc458
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 31 deletions.
67 changes: 55 additions & 12 deletions packages/website/components/contexts/tokensContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { deleteToken, getTokens, createToken } from 'lib/api';
* @property {boolean} isFetchingTokens Whether or not new Tokens are being fetched
* @property {boolean} isCreating Whether or not a new token is being created
* @property {number|undefined} fetchDate The date in which the last Tokens list fetch happened
* @property {string|undefined} errorMessage The error message if any
* @property {boolean} hasError Whether or not there was an error
*/

/**
Expand All @@ -35,37 +37,78 @@ export const TokensProvider = ({ children }) => {
const [isFetchingTokens, setIsFetchingTokens] = useState(false);
const [isCreating, setIsCreating] = useState(false);
const [fetchDate, setFetchDate] = useState(/** @type {number|undefined} */ (undefined));
const [hasError, setHasError] = useState(/** @type {boolean} */ (false));
const [errorMessage, setErrorMessage] = useState(/** @type {string} */ (''));

const processApiError = useCallback(
error => {
if (!error.message) {
setHasError(true);
setErrorMessage('An unknown error has occurred');
return;
}
const errorObject = JSON.parse(
error.message.substring(error.message.indexOf('{'), error.message.lastIndexOf('}') + 1)
);
setHasError(true);
if (errorObject.code === 'ERROR_MAINTENANCE') {
setErrorMessage('Tokens API undergoing maintenance. Please try again later.');
return;
}

setErrorMessage('Tokens API error has occurred. Please try again later.');
},
[setErrorMessage, setHasError]
);

const getTokensCallback = useCallback(
/** @type {() => Promise<Token[]>}} */
async () => {
setIsFetchingTokens(true);
const updatedTokens = await getTokens();
setTokens(updatedTokens);
setIsFetchingTokens(false);
setFetchDate(Date.now());
try {
setIsFetchingTokens(true);
const updatedTokens = await getTokens();
setTokens(updatedTokens);
setIsFetchingTokens(false);
setFetchDate(Date.now());

return updatedTokens;
} catch (e) {
processApiError(e);

return updatedTokens;
return new Promise((resolve, reject) => {
reject(errorMessage);
});
}
},
[setTokens, setFetchDate, setIsFetchingTokens]
[setTokens, setFetchDate, setIsFetchingTokens, processApiError, errorMessage]
);

const createTokensCallback = useCallback(
/** @type {(name: string) => Promise<Token>}} */
async name => {
setIsCreating(true);
const newToken = await createToken(name);
setIsCreating(false);
return newToken;
try {
setIsCreating(true);
const newToken = await createToken(name);
setIsCreating(false);
return newToken;
} catch (e) {
processApiError(e);

return new Promise((resolve, reject) => {
reject(errorMessage);
});
}
},
[setIsCreating]
[setIsCreating, processApiError, errorMessage]
);

return (
<TokensContext.Provider
value={
/** @type {TokensContextProps} */
({
hasError,
errorMessage,
deleteToken,
createToken: createTokensCallback,
getTokens: getTokensCallback,
Expand Down
38 changes: 21 additions & 17 deletions packages/website/components/tokens/tokenCreator/tokenCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const TokenCreator = ({ content }) => {
const [inputHasValue, setInputHasValue] = useState(/** @type {boolean} */ (false));

const { query, push, replace } = useRouter();
const { tokens, createToken, isCreating, getTokens } = useTokens();
const { tokens, createToken, isCreating, getTokens, hasError, errorMessage } = useTokens();

const user = useUser();

Expand Down Expand Up @@ -98,9 +98,9 @@ const TokenCreator = ({ content }) => {
};

return (
<div className={clsx('token-creator-container', isCreating && 'isDisabled')}>
<div className={clsx('token-creator-container', isCreating && !hasError && 'isDisabled')}>
{isCreating ? (
content.loading_message
<> {hasError ? <span>{errorMessage}</span> : content.loading_message} </>
) : (
<>
<form className={clsx(!query.create && 'hidden', 'token-creator-input-container')} onSubmit={onTokenCreate}>
Expand All @@ -116,20 +116,24 @@ const TokenCreator = ({ content }) => {
/>
<button className="token-creator-submit">{inputHasValue ? '→' : '+'}</button>
</form>
<Button
disabled={user?.info?.tags?.['HasAccountRestriction']}
className={clsx('token-creator-create', query.create && 'hidden')}
href="/account"
onClick={() => push('/tokens?create=true')}
variant={ButtonVariant.TEXT}
tooltip={
user?.info?.tags?.['HasAccountRestriction']
? 'You are unable to create API tokens when your account is blocked. Please contact support@web3.storage'
: ''
}
>
{content.prompt}
</Button>
{hasError ? (
<>{errorMessage}</>
) : (
<Button
disabled={user?.info?.tags?.['HasAccountRestriction']}
className={clsx('token-creator-create', query.create && 'hidden')}
href="/account"
onClick={() => push('/tokens?create=true')}
variant={ButtonVariant.TEXT}
tooltip={
user?.info?.tags?.['HasAccountRestriction']
? 'You are unable to create API tokens when your account is blocked. Please contact support@web3.storage'
: ''
}
>
{content.prompt}
</Button>
)}
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const defaultQueryOrder = 'a-z';
* @returns
*/
const TokensManager = ({ content }) => {
const { tokens, fetchDate, isFetchingTokens, deleteToken, getTokens, isCreating } = useTokens();
const { tokens, fetchDate, isFetchingTokens, deleteToken, getTokens, isCreating, hasError, errorMessage } = useTokens();
const [deletingTokenId, setDeletingTokenId] = useState('');
const { query, replace } = useRouter();
const queryClient = useQueryClient();
Expand Down Expand Up @@ -128,7 +128,13 @@ const TokensManager = ({ content }) => {
<TokenRowItem name={tokenRowLabels.name.label} secret={tokenRowLabels.secret.label} isHeader />
<div className="tokens-manager-table-content">
{isFetchingTokens || !fetchDate ? (
<Loading className={'tokens-manager-loading-spinner'} />
<>
{hasError ? (
<div className="table-error">{errorMessage}</div>
) : (
<Loading className={'tokens-manager-loading-spinner'} />
)}
</>
) : !tokens.length ? (
<span className="tokens-manager-upload-cta">
{content.table.message}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@
min-height: auto;
}

.table-error {
padding: 1.875rem;
text-align: center;
color: $cyan;
}

.tokens-manager-upload-cta {
position: relative;
top: 1.5625rem;
Expand Down

0 comments on commit cabc458

Please sign in to comment.