/* ┌──────────────────────────────────────────────────────────────────┐ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │ │ Copyright (c) 2025 Ivan Murzak │ │ Licensed under the Apache License, Version 2.0. │ │ See the LICENSE file in the project root for more information. │ └──────────────────────────────────────────────────────────────────┘ */ #nullable enable using System; using System.IO; using System.Linq; using System.Net.Http; using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization.Metadata; using System.Threading.Tasks; using com.IvanMurzak.Unity.MCP.Editor.Utils; using UnityEditor; using UnityEditor.PackageManager; using UnityEngine; using UnityEngine.UIElements; namespace com.IvanMurzak.Unity.MCP.Editor.UI { /// /// Reusable extension item component backed by the ExtensionItem.uxml template. /// Displays an extension name, description, and install/update button with progress tracking. /// Installs packages via OpenUPM scoped registry in manifest.json. /// public class ExtensionPanel { private static readonly string[] TemplatePaths = EditorAssetLoader.GetEditorAssetPaths("Editor/UI/uxml/ExtensionItem.uxml"); private const string RegistryName = "package.openupm.com"; private const string RegistryUrl = "https://package.openupm.com"; private static readonly string[] RequiredScopes = { "com.ivanmurzak", "extensions.unity", "org.nuget.com.ivanmurzak", "org.nuget.microsoft", "org.nuget.system", "org.nuget.r3" }; private readonly Label _name; private readonly Label _description; private readonly Button _actionBtn; private readonly ExtensionData _data; /// /// The root visual element of the extension panel. Add this to a parent container. /// public VisualElement Root { get; } /// /// Creates a new extension panel from the UXML template. /// Button is hidden until determines the correct state. /// /// The extension data including name, description, package ID, and tools list. public ExtensionPanel(ExtensionData data) { _data = data; var template = EditorAssetLoader.LoadAssetAtPath(TemplatePaths) ?? throw new NullReferenceException($"Failed to load ExtensionItem.uxml. Checked: {string.Join(", ", TemplatePaths)}"); var tree = template.CloneTree(); Root = tree.Q("extension-item") ?? throw new NullReferenceException("VisualElement 'extension-item' not found in ExtensionItem.uxml."); _name = Root.Q