Skip to content

AI Request Logs: "Copy Log ID" gives no feedback when copied #699

Description

@hbhalodia

Description

In the AI Request Logs detail modal (src/admin/ai-request-logs/components/LogDetailModal.tsx), the Copy Log ID button copies the log ID to the clipboard, but there is no visual or accessible feedback to confirm the copy succeeded. The user clicks the button and nothing appears to happen, leaving them unsure whether the copy worked.

By contrast, the Meta Description experiment's modal (src/experiments/meta-description/components/MetaDescriptionModal.tsx) already does this well — its copy button briefly changes its label to "Copied!" and announces the action to assistive technology.

Step-by-step reproduction instructions

  1. Enable request logging and generate at least one AI request so a log entry exists.
  2. Open AI → Request Logs and click a log row to open the detail modal.
  3. Click the Copy Log ID button in the modal footer.
  4. Observe the button.

Expected behavior

After clicking, the button should give immediate feedback — e.g. change its label to "Copied!" for a few seconds and announce the success to screen readers — then revert to "Copy Log ID".

Actual behavior

The ID is copied to the clipboard, but the button label and UI do not change, and nothing is announced. There is no indication the copy succeeded.

Proposed solution

Mirror the existing pattern from MetaDescriptionModal's copy button: track a transient hasCopied state, swap the label to "Copied!" on success, announce via @wordpress/a11y's speak(), and reset after a short timeout.

Screenshots, screen recording, code snippet

Screen.Recording.2026-06-11.at.4.39.33.PM.mov

Refactor opportunity: shared hook

Rather than duplicating this logic in each component, the copy-with-confirmation behavior should be extracted into a small reusable hook so every "copy" button across the plugin behaves consistently. Suggested shape:

// src/hooks/use-copy-to-clipboard-feedback.ts
import { speak } from '@wordpress/a11y';
import { useCopyToClipboard } from '@wordpress/compose';
import { useEffect, useRef, useState } from '@wordpress/element';

interface UseCopyToClipboardFeedbackOptions {
	/** The text to copy, or a function that returns it. */
	text: string | ( () => string );
	/** Message announced to assistive technology on copy. */
	announcement?: string;
	/** How long the confirmation state stays active, in ms. @default 4000 */
	timeout?: number;
}

export function useCopyToClipboardFeedback< T extends HTMLElement >( {
	text,
	announcement,
	timeout = 4000,
}: UseCopyToClipboardFeedbackOptions ): {
	ref: ( node: T | null ) => void;
	hasCopied: boolean;
} {
	const [ hasCopied, setHasCopied ] = useState( false );
	const timeoutRef = useRef< ReturnType< typeof setTimeout > >();

	const ref = useCopyToClipboard< T >( text, () => {
		if ( announcement ) {
			speak( announcement );
		}
		setHasCopied( true );
		if ( timeoutRef.current ) {
			clearTimeout( timeoutRef.current );
		}
		timeoutRef.current = setTimeout( () => setHasCopied( false ), timeout );
	} );

	useEffect( () => {
		return () => {
			if ( timeoutRef.current ) {
				clearTimeout( timeoutRef.current );
			}
		};
	}, [] );

	return { ref, hasCopied };
}

Usage in LogDetailModal:

const { ref: copyIdRef, hasCopied } =
	useCopyToClipboardFeedback< HTMLButtonElement >( {
		text: log.id,
		announcement: __( 'Log ID copied to clipboard.', 'ai' ),
	} );

// …

<Button ref={ copyIdRef } variant="secondary" size="small">
	{ hasCopied ? __( 'Copied!', 'ai' ) : __( 'Copy Log ID', 'ai' ) }
</Button>

Then refactor MetaDescriptionModal's existing copy button to consume the same hook, removing the duplicated state/timer/speak logic.

Benefits

  • Consistent copy feedback (visual + screen-reader) everywhere.
  • Removes duplicated timer/cleanup boilerplate.
  • A single, tested place to adjust the confirmation duration or announcement behavior in future.

Affected files

  • src/admin/ai-request-logs/components/LogDetailModal.tsx (missing feedback — primary bug)
  • src/experiments/meta-description/components/MetaDescriptionModal.tsx (existing pattern to consolidate)
  • src/hooks/use-copy-to-clipboard-feedback.ts (new shared hook)

Environment info

  • WordPress 7.0
  • AI Plugin develop branch

AI Usage

  • Claude Code, Opus 4.8
  • Used for drafting the issue and implementation.
  • Implementation was then tested, and reviewed before raising the PR.

Please confirm that you have searched existing issues in the repo.

  • Yes

Please confirm that you have tested with all plugins deactivated except the AI plugin.

  • Yes

Please confirm which theme type you used for testing.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure

Metadata

Metadata

Assignees

Labels

[Type] BugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions