Skip to content

Commit

Permalink
Title Optimization: improve error handling (#39340)
Browse files Browse the repository at this point in the history
* Save the error object so we can use it to display the error message

* Move error message to it's own component

* Show the provided error message when the error is related to moderation

* Use an error notice to show the errors

* Show FairUsageNotice when the error is a quota exceeded one

* Changelog

* Use the QuotaExceededMessage component so we handle automatically the free and paid plan quotas

* Support JSON error handling

* Reuse the generic error message

* Change code to trust the message provided by the error object, when available

* Do not show retry button when the error will not go away

* Include type suggestions
  • Loading branch information
lhkowalski authored and gogdzl committed Oct 25, 2024
1 parent 7d84795 commit d6da724
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: other

Title Optimization: properly handle errors and show the correct UI for each.
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
/**
* External dependencies
*/
import { useAiSuggestions } from '@automattic/jetpack-ai-client';
import {
useAiSuggestions,
RequestingErrorProps,
ERROR_QUOTA_EXCEEDED,
ERROR_NETWORK,
ERROR_SERVICE_UNAVAILABLE,
ERROR_UNCLEAR_PROMPT,
} from '@automattic/jetpack-ai-client';
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import { Button, Spinner, ExternalLink } from '@wordpress/components';
import { Button, Spinner, ExternalLink, Notice } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import QuotaExceededMessage from '../../../../blocks/ai-assistant/components/quota-exceeded-message';
import { getFeatureAvailability } from '../../../../blocks/ai-assistant/lib/utils/get-feature-availability';
import useAutoSaveAndRedirect from '../../../../shared/use-autosave-and-redirect';
import usePostContent from '../../hooks/use-post-content';
Expand All @@ -25,6 +33,43 @@ const isKeywordsFeatureAvailable = getFeatureAvailability(
'ai-title-optimization-keywords-support'
);

/**
* A generic error message that we can reuse.
*/
const genericErrorMessage = __(
'The generation of your suggested titles failed. Please try again.',
'jetpack'
);

const ERROR_JSON_PARSE = 'json-parse-error';
type TitleOptimizationJSONError = {
code: typeof ERROR_JSON_PARSE;
message: string;
};

type TitleOptimizationError = RequestingErrorProps | TitleOptimizationJSONError;

const TitleOptimizationErrorMessage = ( { error }: { error: TitleOptimizationError } ) => {
if ( error.code === ERROR_QUOTA_EXCEEDED ) {
return (
<div className="jetpack-ai-title-optimization__error">
<QuotaExceededMessage useLightNudge={ true } />
</div>
);
}

// Use the provided message, if available, otherwise use the generic error message
const errorMessage = error.message ? error.message : genericErrorMessage;

return (
<div className="jetpack-ai-title-optimization__error">
<Notice status="error" isDismissible={ false }>
{ errorMessage }
</Notice>
</div>
);
};

export default function TitleOptimization( {
placement,
busy,
Expand Down Expand Up @@ -58,7 +103,7 @@ export default function TitleOptimization( {
const [ isTitleOptimizationModalVisible, setIsTitleOptimizationModalVisible ] = useState( false );
const [ generating, setGenerating ] = useState( false );
const [ options, setOptions ] = useState( [] );
const [ error, setError ] = useState( false );
const [ error, setError ] = useState< TitleOptimizationError | null >( null );
const [ optimizationKeywords, setOptimizationKeywords ] = useState( '' );
const { editPost } = useDispatch( 'core/editor' );
const { autosave } = useAutoSaveAndRedirect();
Expand All @@ -80,16 +125,20 @@ export default function TitleOptimization( {
setOptions( parsedContent );
setSelected( parsedContent?.[ 0 ]?.title );
} catch ( e ) {
// Do nothing
const jsonError: TitleOptimizationJSONError = {
code: ERROR_JSON_PARSE,
message: genericErrorMessage,
};
setError( jsonError );
}
},
[ increaseAiAssistantRequestsCount ]
);

const { request, stopSuggestion } = useAiSuggestions( {
onDone: handleDone,
onError: () => {
setError( true );
onError: ( e: RequestingErrorProps ) => {
setError( e );
setGenerating( false );
},
} );
Expand Down Expand Up @@ -127,7 +176,7 @@ export default function TitleOptimization( {
}, [ handleRequest, toggleTitleOptimizationModal ] );

const handleTryAgain = useCallback( () => {
setError( false );
setError( null );
handleRequest( true ); // retry the generation
}, [ handleRequest ] );

Expand Down Expand Up @@ -160,6 +209,14 @@ export default function TitleOptimization( {
stopSuggestion();
}, [ stopSuggestion, toggleTitleOptimizationModal ] );

// When can we retry?
const showTryAgainButton =
error &&
[ ERROR_JSON_PARSE, ERROR_NETWORK, ERROR_SERVICE_UNAVAILABLE, ERROR_UNCLEAR_PROMPT ].includes(
error.code
);
const showReplaceTitleButton = ! error;

return (
<div>
<p>{ sidebarDescription }</p>
Expand Down Expand Up @@ -190,12 +247,7 @@ export default function TitleOptimization( {
) : (
<>
{ error ? (
<div className="jetpack-ai-title-optimization__error">
{ __(
'The generation of your suggested titles failed. Please try again.',
'jetpack'
) }
</div>
<TitleOptimizationErrorMessage error={ error } />
) : (
<>
{ isKeywordsFeatureAvailable && (
Expand Down Expand Up @@ -226,11 +278,12 @@ export default function TitleOptimization( {
<Button variant="secondary" onClick={ toggleTitleOptimizationModal }>
{ __( 'Cancel', 'jetpack' ) }
</Button>
{ error ? (
{ showTryAgainButton && (
<Button variant="primary" onClick={ handleTryAgain }>
{ __( 'Try again', 'jetpack' ) }
</Button>
) : (
) }
{ showReplaceTitleButton && (
<Button variant="primary" onClick={ handleAccept }>
{ __( 'Replace title', 'jetpack' ) }
</Button>
Expand Down

0 comments on commit d6da724

Please sign in to comment.