import { useEffect, useState } from 'react'; import { Alert, AlertTitle, Box, Button } from '@mui/material'; import { HttpError, isHttpError } from '../client/HttpError'; import { useDialogContext } from './dialogContext'; import { NewTabLink } from './Link'; import { createUrl } from '../../tools/url'; import { detectExtension, openPlugin } from '../../tools/extension'; import { CHROME_EXTENSION_LINK } from '../../constants'; type Props = { error: HttpError | Error; severity?: 'error' | 'info'; }; export const ErrorAlert = ({ error, severity }: Props) => { const apiUrl = useDialogContext((c) => c.uiProps.apiUrl); return ( {isHttpError(error) ? getErrorContent(error, createUrl(apiUrl).toString()) : error.message} ); }; // Missing credentials, in the page or in the extension, is the normal state of a page nobody has connected yet, // not a failure. export function severityFor(error: HttpError | Error): 'error' | 'info' { return isHttpError(error) && (error.code === 'api_key_not_specified' || error.code === 'extension_session_missing' || error.code === 'extension_editing_off') ? 'info' : 'error'; } function DocsInContext() { return ( Learn more in Docs ); } function OpenExtension() { const [present, setPresent] = useState(); useEffect(() => { let mounted = true; detectExtension().then((found) => mounted && setPresent(found)); return () => { mounted = false; }; }, []); if (present === undefined) { return null; } return ( {present ? ( ) : ( )} ); } function DocsAPIKeys() { return ( Learn more in Docs ); } export function getErrorContent( { code, params, message }: HttpError, apiUrl: string ) { switch (code) { case 'operation_not_permitted': return ( <> Operation not permitted {Boolean(params?.length) && 'Missing scopes: ' + params?.join(', ')} ); case 'invalid_project_api_key': return ( <> Invalid API key Check it in the code or in the chrome plugin. ); case 'unauthenticated': case 'invalid_jwt_token': case 'expired_jwt_token': case 'general_jwt_error': case 'invalid_oauth_token': case 'oauth_token_expired': case 'extension_session_missing': return ( <> You're not signed in Sign in again in the Tolgee plugin to keep editing. ); case 'extension_request_too_large': return ( <> Image is too large to upload This image is too large for the Tolgee plugin to send. Pick a smaller one. ); case 'api_url_not_specified': return ( <> Oops... I miss the API url Add it in the code or via the chrome plugin. ); case 'api_url_not_valid': return ( <> API url is not correct ({apiUrl}) Check it in the code or in the chrome plugin. ); case 'api_key_not_specified': return ( <> Sign in to make changes To edit strings here, sign in with the Tolgee browser extension or add an API key to the Tolgee configuration. ); case 'extension_editing_off': return ( <> In-context editing is switched off You switched editing off for this page in the Tolgee plugin. Turn it on to edit here. ); case 'project_id_not_specified': return ( <> Oops... I miss the project id An OAuth token or PAT carries no project, so projectId must be set in the Tolgee configuration. ); case 'project_not_found': return ( <> Project not found The configured project doesn't exist on this server, or your account can't access it. Check the projectId in the Tolgee configuration, or ask for access. ); case 'permissions_not_sufficient_to_edit': return ( <> Sorry, you don't have permissions to make changes Update your API key or ask admin for more permissions ); case 'operation_not_permitted_in_read_only_mode': return ( <> Read-only mode This branch is protected or your access is read-only. ); case 'branch_not_found': return ( <> Branch not found Check the branch name or switch to an existing branch. ); case 'fetch_error': return `Failed to fetch (${apiUrl})`; default: return message; } }