manager = $manager; } /** * Registers the Tools page. */ public function register_menu(): void { $page_hook = add_submenu_page( 'tools.php', __( 'AI Request Logs', 'ai' ), __( 'AI Request Logs', 'ai' ), 'manage_options', self::PAGE_SLUG, array( $this, 'render_page' ) ); if ( ! $page_hook ) { return; } add_action( "load-{$page_hook}", array( $this, 'on_load' ) ); } /** * Ensures assets are loaded when the page is visited. */ public function on_load(): void { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); } /** * Enqueues the React bundle and passes localized data. */ public function enqueue_assets(): void { Asset_Loader::enqueue_dataviews_style(); Asset_Loader::enqueue_script( 'ai_request_logs', 'admin/ai-request-logs' ); Asset_Loader::enqueue_style( 'ai_request_logs', 'admin/ai-request-logs' ); /* * Explicitly load translations for the `wp-dataviews` script. * The DataViews component ships its own UI strings that are only * inlined by WordPress in block-editor contexts. */ wp_set_script_translations( 'wp-dataviews', 'default' ); Asset_Loader::localize_script( 'ai_request_logs', 'RequestLogsSettings', array( 'rest' => array( 'nonce' => wp_create_nonce( 'wp_rest' ), 'root' => esc_url_raw( rest_url() ), 'routes' => array( 'logs' => 'ai/v1/logs', 'summary' => 'ai/v1/logs/summary', 'filters' => 'ai/v1/logs/filters', ), ), 'initialState' => array( 'summary' => $this->manager->get_summary( 'day' ), 'filters' => $this->manager->get_filter_options(), ), 'connectorsUrl' => admin_url( 'options-connectors.php' ), 'providerMetadata' => $this->get_provider_metadata(), ) ); } /** * Outputs the root DOM node for the React app. */ public function render_page(): void { if ( ! current_user_can( 'manage_options' ) ) { return; } ?>