page_slug, [ $this, 'render_dashboard_page' ], 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCAyNTYgMjU2Ij48cGF0aCBmaWxsPSIjYTdhYWFkIiBkPSJNNjkuNCAxNC40Yy0uOS44LTEgMy40LTEgMTguOSAwIDE2LjcuMSAxOC4xIDEuMSAxOSAuNi42IDEuNSAxIDIgMXM5LjgtMi4zIDIwLjctNWwxOS44LTUgMi44IDIuOWM3LjggOC4xIDE5LjUgOC4yIDI3LjMuNWwzLjQtMy40IDIwLjEgNS4xYzEyLjggMy4zIDIwLjUgNC45IDIxLjQgNC42LjctLjIgMS42LTEuMSAyLTIgLjMtLjguNi04LjkuNi0xNy45IDAtMTcuOS0uMi0xOS40LTMuMi0xOS43LS45LS4xLTEwLjUgMi0yMS4zIDQuOGwtMTkuNyA1LTIuOC0zLjFjLTMuOS00LjEtNy45LTUuOC0xMy44LTUuOS01LjcgMC0xMC40IDItMTQuMSA2LjJsLTIuNSAyLjgtMTkuNC00LjljLTEwLjYtMi44LTIwLTUtMjAuOS01LS45LjEtMiAuNS0yLjUgMS4xeiIvPjxwYXRoIGZpbGw9IiNhN2FhYWQiIGQ9Ik0yNS4yIDUyLjRjLTYgMy41LTExLjUgNi44LTEyLjIgNy40LTMuMSAyLjgtMy0xLjctMyA5MS4xIDAgNjMuNC4yIDg3LjEuNyA4OC4yIDEuNyAzLjYtNSAzLjQgMTE3LjMgMy40czExNS43LjIgMTE3LjMtMy40Yy41LTEuMS43LTI0LjIuNy04NS43IDAtODIuOCAwLTg0LjItMS4yLTg2LjYtMS4zLTIuNi0yLTMuMy0xNS40LTEzLjgtNC45LTMuOS05LjEtNi44LTkuMy02LjYtLjIuMi0xOS40IDM3LjEtNDIuNyA4MS45LTIzLjIgNDQuOC00My44IDg0LjMtNDUuNyA4Ny44bC0zLjQgNi4zLTQuMS03LjktNDUuOC04Ny44Yy0yMi45LTQzLjktNDEuNy04MC4xLTQyLTgwLjMtLjEtLjEtNS4yIDIuNS0xMS4yIDZ6Ii8+PHBhdGggZmlsbD0iI2E3YWFhZCIgZD0iTTEyNS42IDc2LjdjLTcuOSAxLjUtMTMuNCA5LjgtMTEuNyAxNy44IDIuOCAxMi45IDE5LjQgMTYuNiAyNyA2IDguMS0xMS4yLTEuNy0yNi4zLTE1LjMtMjMuOHpNMTIzLjYgMTI4YTE0LjQgMTQuNCAwIDAgMC04LjIgNy41Yy0zLjEgNi4zLTEuOCAxMy42IDMuMyAxOC4xIDMuMSAyLjcgNS43IDMuNiAxMCAzLjYgNC40IDAgNy42LTEuMiAxMC4zLTMuOSA5LjctOS4zIDQuMS0yNS4yLTkuMy0yNi0yLjQtLjEtNC43LjEtNi4xLjd6Ii8+PC9zdmc+', 80 ); // Add Dashboard submenu (replaces auto-generated first submenu). add_submenu_page( $this->parent_slug, __( 'Dashboard', 'albert-ai-butler' ), __( 'Dashboard', 'albert-ai-butler' ), 'manage_options', $this->page_slug, [ $this, 'render_dashboard_page' ] ); } /** * Enqueue dashboard assets. * * @param string $hook Current admin page hook. * * @return void * @since 1.0.0 */ public function enqueue_assets( string $hook ): void { // Only load on our dashboard page. if ( 'toplevel_page_albert' !== $hook ) { return; } wp_enqueue_style( 'albert-admin', ALBERT_PLUGIN_URL . 'assets/css/admin-settings.css', [], ALBERT_VERSION ); wp_enqueue_script( 'albert-dashboard', ALBERT_PLUGIN_URL . 'assets/js/admin-dashboard.js', [], ALBERT_VERSION, true ); } /** * Render dashboard page. * * @return void * @since 1.0.0 */ public function render_dashboard_page(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'albert-ai-butler' ) ); } // Gather setup state. $has_allowed_users = ! empty( get_option( 'albert_allowed_users', [] ) ); $active_connections = $this->get_active_connections_count(); $has_connections = $active_connections > 0; $setup_complete = $has_allowed_users && $has_connections; $enabled_abilities = $this->get_enabled_abilities_count(); $mcp_endpoint = McpServer::get_endpoint_url(); ?>
get_var( $wpdb->prepare( 'SELECT COUNT(DISTINCT client_id) FROM %i WHERE revoked = 0', $tables['access_tokens'] ) ); return (int) $count; } /** * Get count of enabled abilities. * * @return string Enabled/Total abilities count. * @since 1.0.0 */ private function get_enabled_abilities_count(): string { $disabled_abilities = AbstractAbilitiesPage::get_disabled_abilities(); $all_abilities = wp_get_abilities(); $enabled_count = 0; $total_count = count( $all_abilities ); foreach ( $all_abilities as $ability ) { $name = $ability->get_name(); // Ability is enabled if NOT in the disabled list. if ( ! in_array( $name, $disabled_abilities, true ) ) { ++$enabled_count; } } return sprintf( '%d/%d', $enabled_count, $total_count ); } /** * Get recent activity from OAuth sessions. * * @return array