diff --git a/scripts/execute-vscode-sideload.ps1 b/scripts/execute-vscode-sideload.ps1 new file mode 100644 index 0000000000..7352e36676 --- /dev/null +++ b/scripts/execute-vscode-sideload.ps1 @@ -0,0 +1,36 @@ +param ( + [string] + [Parameter(Mandatory = $false)] + $Platform = "win-x64", + [switch] + $WSL +) + + +Push-Location ./vscode/microsoft-kiota + +# Install all dependencies +npm i + +# Package the VS Code extension +npx @vscode/vsce package + +# Getting package for its version +$PackageJson = Get-Content "package.json" -Raw | ConvertFrom-Json + +# Install the extension +code --install-extension "./kiota-$($PackageJson.version).vsix" + +$VsCodeRootPath = (Resolve-Path "~/.vscode").Path + +if ($WSL) { + $Platform = "linux-x64" + $VsCodeRootPath = (Resolve-Path "~/.vscode-server").Path +} + +$KiotaBin = "$VsCodeRootPath/extensions/ms-graph.kiota-$($PackageJson.version)/.kiotabin/$($PackageJson.kiotaVersion)/$Platform" + +Pop-Location + +# Building Kiota +dotnet publish ./src/kiota/kiota.csproj -p:PublishSingleFile=true -p:PublishReadyToRun=true --self-contained -c Release -r $platform -o $KiotaBin \ No newline at end of file diff --git a/src/kiota/Rpc/IServer.cs b/src/kiota/Rpc/IServer.cs index 5c467acdbe..de7a284c0a 100644 --- a/src/kiota/Rpc/IServer.cs +++ b/src/kiota/Rpc/IServer.cs @@ -10,7 +10,8 @@ internal interface IServer Task SearchAsync(string searchTerm, bool clearCache, CancellationToken cancellationToken); Task ShowAsync(string descriptionPath, string[] includeFilters, string[] excludeFilters, bool clearCache, CancellationToken cancellationToken); Task GetManifestDetailsAsync(string manifestPath, string apiIdentifier, bool clearCache, CancellationToken cancellationToken); - Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, CancellationToken cancellationToken); + Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, ConsumerOperation operation, CancellationToken cancellationToken); Task InfoForDescriptionAsync(string descriptionPath, bool clearCache, CancellationToken cancellationToken); - Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, CancellationToken cancellationToken); + Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, ConsumerOperation operation, CancellationToken cancellationToken); + Task> MigrateFromLockFileAsync(string lockDirectoryPath, CancellationToken cancellationToken); } diff --git a/src/kiota/Rpc/Server.cs b/src/kiota/Rpc/Server.cs index 871f20bb54..66634daed2 100644 --- a/src/kiota/Rpc/Server.cs +++ b/src/kiota/Rpc/Server.cs @@ -4,6 +4,7 @@ using Kiota.Builder.Extensions; using Kiota.Builder.Lock; using Kiota.Builder.Logging; +using Kiota.Builder.WorkspaceManagement; using Kiota.Generated; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -137,7 +138,7 @@ private static string NormalizeOperationNodePath(OpenApiUrlTreeNode node, Operat return indexingNormalizationRegex().Replace(name, "{}"); return name; } - public async Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, CancellationToken cancellationToken) + public async Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, ConsumerOperation operation, CancellationToken cancellationToken) { var logger = new ForwardedLogger(); var configuration = Configuration.Generation; @@ -151,7 +152,7 @@ public async Task> GenerateAsync(string openAPIFilePath, string o configuration.ClearCache = clearCache; configuration.ExcludeBackwardCompatible = excludeBackwardCompatible; configuration.IncludeAdditionalData = includeAdditionalData; - configuration.Operation = ConsumerOperation.Add; //TODO should be updated to edit in the edit scenario + configuration.Operation = operation; if (disabledValidationRules is { Length: > 0 }) configuration.DisabledValidationRules = disabledValidationRules.ToHashSet(StringComparer.OrdinalIgnoreCase); if (serializers is { Length: > 0 }) @@ -183,7 +184,7 @@ public async Task> GenerateAsync(string openAPIFilePath, string o } return logger.LogEntries; } - public async Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, CancellationToken cancellationToken) + public async Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, ConsumerOperation operation, CancellationToken cancellationToken) { var globalLogger = new ForwardedLogger(); var configuration = Configuration.Generation; @@ -194,7 +195,7 @@ public async Task> GeneratePluginAsync(string openAPIFilePath, st configuration.ClientClassName = clientClassName; configuration.CleanOutput = cleanOutput; configuration.ClearCache = clearCache; - configuration.Operation = ConsumerOperation.Add; //TODO should be updated to edit in the edit scenario + configuration.Operation = operation; if (disabledValidationRules is { Length: > 0 }) configuration.DisabledValidationRules = disabledValidationRules.ToHashSet(StringComparer.OrdinalIgnoreCase); if (pluginTypes is { Length: > 0 }) @@ -230,6 +231,28 @@ public Task InfoForDescriptionAsync(string descriptionPath ArgumentException.ThrowIfNullOrEmpty(descriptionPath); return InfoInternalAsync(descriptionPath, clearCache, cancellationToken); } + + public async Task> MigrateFromLockFileAsync(string lockDirectoryPath, CancellationToken cancellationToken) + { + ArgumentException.ThrowIfNullOrEmpty(lockDirectoryPath); + var logger = new ForwardedLogger(); + try + { + var workspaceManagementService = new WorkspaceManagementService(logger, httpClient, IsConfigPreviewEnabled.Value); + var clientNames = await workspaceManagementService.MigrateFromLockFileAsync(string.Empty, lockDirectoryPath, cancellationToken).ConfigureAwait(false); + if (!clientNames.Any()) + { + logger.LogWarning("no client configuration was migrated"); + } + logger.LogInformation("Client configurations migrated successfully: {Clients}", string.Join(", ", clientNames)); + } + catch (Exception ex) + { + logger.LogCritical(ex, "error migrating the lock file: {ExceptionMessage}", ex.Message); + } + return logger.LogEntries; + } + private async Task InfoInternalAsync(string descriptionPath, bool clearCache, CancellationToken cancellationToken) { var logger = new ForwardedLogger(); @@ -257,7 +280,10 @@ private static PathItem ConvertOpenApiUrlTreeNodeToPathItem(OpenApiUrlTreeNode n .OrderByDescending(static x => x.isOperation) .ThenBy(static x => x.segment, StringComparer.OrdinalIgnoreCase) .ToArray(); - return new PathItem(node.Path, node.DeduplicatedSegment(), children, filteredPaths.Count == 0 || Array.Exists(children, static x => x.isOperation) && children.Where(static x => x.isOperation).All(static x => x.selected)); + bool isSelected = filteredPaths.Count == 0 || // There are no filtered paths + Array.Exists(children, static x => x.isOperation) && children.Where(static x => x.isOperation).All(static x => x.selected) || // All operations have been selected + !Array.Exists(children, static x => x.isOperation) && Array.TrueForAll(children, static x => x.selected); // All paths selected but no operations present + return new PathItem(node.Path, node.DeduplicatedSegment(), children, isSelected); } private static string GetAbsolutePath(string source) { diff --git a/vscode/microsoft-kiota/debugging.md b/vscode/microsoft-kiota/debugging.md index 8f5fda2247..a4e6564fc7 100644 --- a/vscode/microsoft-kiota/debugging.md +++ b/vscode/microsoft-kiota/debugging.md @@ -17,7 +17,7 @@ Context: you're most likely a program manager eager to demo the latest bits from - GitHub CLI `winget install GitHub.CLI` - dotnet 8 `winget install Microsoft.DotNet.SDK.8` - node 20 `winget install CoreyButler.NVMforWindows && nvm install lts && nvm use lts` -- vsce & TypeScript `npm i -g TypeScript @vscode/vsce` +- vsce & TypeScript `npm i -g typescript @vscode/vsce` ### Steps @@ -46,3 +46,27 @@ Where kiotaVersionInPackage is the kiotaVersion field and versionInPackage is th > Note: the **.vscode** segment might change to **.vscode-server** if you're remoting to WSL. > Note: alternatively to building executable yourself, you can download it from [the pipeline](https://github.com/microsoft/kiota/actions/workflows/dotnet.yml) by filtering the branch (top right corner) with the pull request branch, selecting the latest run, and downloading the right OS version from the artifacts. The only remaining work will be to move the downloaded files to the right path above. + +#### Using the ready-made script + +If you want to automate these steps, you can use the following script to automate the process: + +```powershell +.\scripts\execute-vscode-sideload.ps1 -Platform "win-x64|linux-x64|osx-x64" +``` + +If you are using WSL, you can use the following: + +```powershell +.\scripts\execute-vscode-sideload.ps1 -WSL +``` + +## FAQ + +### VS Code keeps reinstalling from the marketplace + +This is most likely caused by the fact that there's a newer released version. Run the following script replacing the version argument with the latest version of kiota. + +```powershell +.\scripts\update-vscode-releases.ps1 -version "versionWithoutVPrefix" -online -filePath .\vscode\microsoft-kiota\package.json +``` diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.ar.json b/vscode/microsoft-kiota/l10n/bundle.l10n.ar.json index 797dd1b706..e07761be5e 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.ar.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.ar.json @@ -28,7 +28,6 @@ "Generating client...": "انشاء العميل...", "Loading...": "جاري التحميل...", "Updating clients...": "تحديث العملاء...", - "Pick a lock file": "اختر ملف قفل", "Open a lock file": "افتح ملف قفل", "Filter the API description": "قم بتصفية وصف API", "Enter a filter": "أدخل عامل التصفية", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "عنوان URL غير صالح ، يرجى التحقق من الوثائق الخاصة بعناوين URL المدعومة", "No content found in the clipboard": "لم يتم العثور على محتوى في الحافظة", "Invalid content found in the clipboard": "تم العثور على محتوى غير صالح في الحافظة", - "Select an API manifest key": "حدد مفتاح بيان واجهة برمجة التطبيقات" + "Select an API manifest key": "حدد مفتاح بيان واجهة برمجة التطبيقات", + "Edit Paths":"تحرير المسارات", + "Re-generate": "تجديد", + "Add an API description": "إضافة وصف API", + "Search or paste a path to an API description": "ابحث أو الصق مسارًا إلى وصف API", + "Generate a plugin": "إنشاء البرنامج المساعد", + "Generate an API manifest": "إنشاء بيان API", + "What do you want to generate?" : "ماذا تريد أن تولد؟", + "Select an option": " حدد خيارًا", + "class": "فئة", + "namespace": "مساحة الاسم", + "output directory": "مجلد الإخراج", + "language": "لغة", + "Create a new API client": "إنشاء عميل API جديد", + "Create a new plugin": "إنشاء مكون إضافي جديد", + "Create a new manifest": "إنشاء بيان API جديد", + "plugin name:": "اسم المكون الإضافي", + "Choose a name for the plugin": "اختر اسمًا للمكون الإضافي", + "Choose a plugin type": "اختر نوع البرنامج المساعد", + "manifest name": "اسم واضح", + "Choose a name for the manifest": "اختر اسمًا للبيان", + "Required": "مطلوب", + "Open installation instructions for kiota?": "هل تريد فتح تعليمات التثبيت لـ kiota؟", + "Invalid generation type": "نوع الجيل غير صالح", + "Yes, override it": "نعم، تجاوزه", + "Before adding a new API description, consider that your changes and current selection will be lost.": "قبل إضافة وصف جديد لواجهة برمجة التطبيقات، ضع في اعتبارك أنه سيتم فقدان التغييرات والاختيار الحالي.", + "Cancel": "يلغي", + "Do you want to remove this API description?": "هل تريد إزالة وصف API هذا؟", + "Please save the workspace.json file before re-generation.": "يرجى حفظ ملف workspace.json قبل إعادة الإنشاء.", + "OK": "حسنا", + "Generating manifest...": "جارٍ إنشاء البيان...", + "Generating plugin...": "جارٍ إنشاء البرنامج المساعد...", + "Re-generating client...": "إعادة إنشاء العميل...", + "Re-generating plugin...": "إعادة إنشاء البرنامج المساعد...", + "Please migrate your API clients to Kiota workspace.":"يرجى ترحيل عملاء API الخاصين بك إلى مساحة العمل Kiota.", + "Remind me later":"ذكرني لاحقًا", + "Migrating your API clients...": "جاري ترحيل عملاء API الخاصين بك...", + "Migration completed, but no changes were detected.": "تم الانتهاء من الترحيل، ولكن لم يتم اكتشاف أي تغييرات.", + "Migration failed":"فشل الترحيل", + "API clients migrated successfully!":"تم ترحيل عملاء API بنجاح!", + "Could not determine the workspace folder.": "لا يمكن تحديد مجلد مساحة العمل." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.cs.json b/vscode/microsoft-kiota/l10n/bundle.l10n.cs.json index 0c7a52d554..8b0304a87c 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.cs.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.cs.json @@ -28,7 +28,6 @@ "Generating client...": "Generování klienta...", "Updating clients...": "Aktualizace klientů...", "Loading...": "Načítání...", - "Pick a lock file": "Vybrat soubor zámku", "Open a lock file": "Otevřít soubor zámku", "Filter the API description": "Filtrovat popis API", "Enter a filter": "Zadejte filtr", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "Neplatná URL adresa, zkontrolujte dokumentaci pro podporované URL adresy", "No content found in the clipboard": "V schránce nebyl nalezen žádný obsah", "Invalid content found in the clipboard": "V schránce byl nalezen neplatný obsah", - "Select an API manifest key": "Vyberte klíč manifestu API" + "Select an API manifest key": "Vyberte klíč manifestu API", + "Edit Paths":"Upravit cesty", + "Re-generate": "Znovu vygenerovat", + "Add an API description": "Přidat popis API", + "Search or paste a path to an API description": "Hledat nebo vložit cestu k popisu API", + "Generate a plugin": "Generovat plugin", + "Generate an API manifest": "Generovat API manifest", + "What do you want to generate?": "Co chcete generovat? ", + "Select an option": "Vyberte možnost", + "class": "třída", + "namespace": "jmenný prostor", + "output directory": "výstupní adresář", + "language": "jazyk", + "Create a new API client": "Vytvořit nového API klienta", + "Create a new plugin": "Vytvořit nový plugin", + "Create a new manifest": "Vytvořit nový manifest", + "plugin name:": "název pluginu", + "Choose a name for the plugin": "Vyberte název pro plugin", + "Choose a plugin type": "Vyberte typ pluginu", + "manifest name": "název manifestu", + "Choose a name for the manifest": "Vyberte název pro manifest", + "Required": "Požadováno", + "Open installation instructions for kiota?": "Otevřít instalační pokyny pro kiota", + "Invalid generation type": "Neplatný typ generování", + "Yes, override it": "Ano, přepsat", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Před přidáním nového popisu API zvažte, že vaše změny a aktuální výběr budou ztraceny.", + "Cancel": "Zrušit", + "Do you want to remove this API description?": "Chcete odstranit tento popis API?", + "Please save the workspace.json file before re-generation.": "Před generováním prosím uložte soubor workspace.json", + "OK": "OK", + "Generating manifest...": "Generování manifestu...", + "Generating plugin...": "Generování pluginu...", + "Re-generating client...": "Opětovné generování klienta...", + "Re-generating plugin...": "Opětovné generování pluginu...", + "Please migrate your API clients to Kiota workspace.":"Prosím, přesuňte své klienty API do pracovního prostoru Kiota.", + "Remind me later":"Připomeňte mi to později", + "Migrating your API clients...":"Přesouvání vašich klientů API…", + "Migration completed, but no changes were detected.":"Migrace dokončena, ale nebyly zjištěny žádné změny.", + "Migration failed":"Migrace selhala.", + "API clients migrated successfully!":"Klienti API byli úspěšně přesunuti!", + "Could not determine the workspace folder.": "Nepodařilo se určit složku pracovního prostoru." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.es.json b/vscode/microsoft-kiota/l10n/bundle.l10n.es.json index 8918ec1050..36a0c7666c 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.es.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.es.json @@ -28,7 +28,6 @@ "Generating client...": "Generando cliente...", "Updating clients...": "Actualizando clientes...", "Loading...": "Cargando...", - "Pick a lock file": "Seleccionar un archivo lock", "Open a lock file": "Abrir un archivo lock", "Filter the API description": "Filtrar descripción de API", "Enter a filter": "Ingresar un filtro", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "URL inválido, por favor revise la documentación de URL soportados.", "No content found in the clipboard": "Sin contenido en el portapapeles.", "Invalid content found in the clipboard": "Contenido inválido en el portapapeles.", - "Select an API manifest key": "Seleccione una llave de manifesto de API." + "Select an API manifest key": "Seleccione una llave de manifesto de API.", + "Edit Paths":"Editar ruta de acceso", + "Re-generate": "Re-generar", + "Add an API description": "Agregar una descripción de API", + "Search or paste a path to an API description": "Busca o pega una ruta a una descripcion de API", + "Generate a plugin": "Generar un plugin", + "Generate an API manifest": "Generar un manifesto de API", + "What do you want to generate?": "Qué quieres generar?", + "Select an option": "Seleccionar una opción", + "class": "clase", + "namespace": "namespace", + "output directory": "directorio de salida", + "language": "idioma", + "Create a new API client": "Crear un nuevo cliente de API", + "Create a new plugin": "Crear un nuevo plugin", + "Create a new manifest": "Crear un nuevo manifesto", + "plugin name:": "nombre del plugin", + "Choose a name for the plugin": "Elija un nombre para el plugin", + "Choose a plugin type": "Elija un tipo de plugin", + "manifest name": "Nombre de manifesto", + "Choose a name for the manifest": "Elija un nombre para el manifesto", + "Required": "Requerido", + "Open installation instructions for kiota?": "Abrir las instrucciones de instalación para Kiota", + "Invalid generation type": "Tipo de generación inválido", + "Yes, override it": "Sí, sobrescribir", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Antes de agregar una nueva descripción de API, considere que sus cambios and selección actual se perderá", + "Cancel": "Cancelar", + "Do you want to remove this API description?": "Quieres quitar esta descripcion de API?", + "Please save the workspace.json file before re-generation.": "Por favor, guarde el archivo workspace.json antes de re-generar.", + "OK": "Ok", + "Generating manifest...": "Generando manifesto...", + "Generating plugin...": "Generando plugin...", + "Re-generating client...": "Re-generando cliente...", + "Re-generating plugin...": "Re-generando plugin...", + "Please migrate your API clients to Kiota workspace.":"Por favor, migre sus clientes API al workspace de Kiota.", + "Remind me later":"Recordarme más tarde", + "Migrating your API clients...":"Migrando sus clients API...", + "Migration completed, but no changes were detected.":"Migración completa, mas no se detectaron cambios.", + "Migration failed":"Migración fallida", + "API clients migrated successfully!":"Clientes API migrados existosamente.", + "Could not determine the workspace folder.": "No se pudo determinar la carpeta de espacio de trabajo." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.fr.json b/vscode/microsoft-kiota/l10n/bundle.l10n.fr.json index d38a9ca7c0..7c1e97b38c 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.fr.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.fr.json @@ -28,7 +28,6 @@ "Generating client...": "Génération du client...", "Updating clients...": "Mise à jour des clients...", "Loading...": "Chargement...", - "Pick a lock file": "Sélectionnez un fichier verrou", "Open a lock file": "Ouvrir un fichier verrou", "Filter the API description": "Filtrer la description d'API", "Enter a filter": "Entrez un filtre", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "URL invalide, veuillez vérifier la documentation pour les URL prises en charge", "No content found in the clipboard": "Aucun contenu trouvé dans le presse-papiers", "Invalid content found in the clipboard": "Contenu non valide trouvé dans le presse-papiers", - "Select an API manifest key": "Sélectionnez une clé de manifeste d'API" + "Select an API manifest key": "Sélectionnez une clé de manifeste d'API", + "Edit Paths": "Modifier les chemins", + "Re-generate": "Générer de nouveau", + "Add an API description": "Ajouter une description d'API", + "Search or paste a path to an API description": "Rechercher ou coller un chemin vers unde description d'API", + "Generate a plugin": "Générer un plugin", + "Generate an API manifest": "Générer un manifeste d'API", + "What do you want to generate?": "Que souhaitez vous générer?", + "Select an option": "Sélectionnez une option", + "class": "classe", + "namespace": "espace de nommage", + "output directory": "répertoire de sortie", + "language": "langage", + "Create a new API client": "Créer un nouveau client d'API", + "Create a new plugin": "Créer un nouveau composant", + "Create a new manifest": "Créer un nouveau manifeste", + "plugin name:": "nom du composant", + "Choose a name for the plugin": "Choisissez un nom pour le composant", + "Choose a plugin type": "Choisisses un type de composant", + "manifest name": "nom du manifeste", + "Choose a name for the manifest": "Choisissez un nom pour le manifeste", + "Required": "Requis", + "Open installation instructions for kiota?": "Ouvrir les instructions d'installation pour kiota?", + "Invalid generation type": "Type de génération invalide", + "Yes, override it": "Oui, l'écraser", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Avant d'ajouter une nouvelle description d'API veuillez noter que vos modifications et sélections actuelles seront perdues", + "Cancel": "Annuler", + "Do you want to remove this API description?": "Voulez-vous supprimer cette description d'API?", + "Please save the workspace.json file before re-generation.": "Veuillez sauvegarder le fichier workspace.json avant de générer à nouveau.", + "OK": "Ok", + "Generating manifest...": "Génération du manifeste...", + "Generating plugin...": "Génération du composant...", + "Re-generating client...": "Rafraichissement du client...", + "Re-generating plugin...": "Refraichissement du composant...", + "Please migrate your API clients to Kiota workspace.": "Veuillez mettre vos clients d'API à jour vers l'expérience d'espace de travail Kiota.", + "Remind me later": "Me le rappeler plus tard", + "Migrating your API clients...": "Migration de vos clients en cours...", + "Migration completed, but no changes were detected.": "Migration terminée, mais aucun changement n'a été détecté.", + "Migration failed": "Echec de la migration", + "API clients migrated successfully!": "Clients d'API migrés avec succès!", + "Could not determine the workspace folder.": "Impossible de déterminer le dossier de l'espace de travail." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.it.json b/vscode/microsoft-kiota/l10n/bundle.l10n.it.json index b9644dbb57..f144de24c3 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.it.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.it.json @@ -28,7 +28,6 @@ "Generating client...": "Generazione del client in corso...", "Updating clients...": "Aggiornamento dei client in corso...", "Loading...": "Caricamento...", - "Pick a lock file": "Seleziona un file di lock", "Open a lock file": "Apri un file di lock", "Filter the API description": "Filtra la descrizione API", "Enter a filter": "Inserisci un filtro", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "URL non valido, controlla la documentazione per gli URL supportati", "No content found in the clipboard": "Nessun contenuto trovato negli appunti", "Invalid content found in the clipboard": "Contenuto non valido trovato negli appunti", - "Select an API manifest key": "Seleziona una chiave del manifest API" + "Select an API manifest key": "Seleziona una chiave del manifest API", + "Edit Paths":"Modifica i percorsi", + "Re-generate": "Rigenera", + "Add an API description": "Aggiungi una descrizione di API", + "Search or paste a path to an API description": "Cerca o incolla un percorso ad un file di descrizione API", + "Generate a plugin": "Genera un plugin", + "Generate an API manifest": "Genera un manifest API", + "What do you want to generate?": "Cosa vuoi generare?", + "Select an option": "Seleziona un'opzione", + "class": "classe", + "namespace": "namespace", + "output directory": "directory di output", + "language": "lingua", + "Create a new API client": "Crea un nuovo client API", + "Create a new plugin": "Crea un nuovo plugin", + "Create a new manifest": "Crea un nuovo manifest", + "plugin name": "nome del plugin", + "Choose a name for the plugin": "Scegli un nome per il plugin", + "Choose a plugin type": "Scegli un tipo di plugin", + "manifest name": "Nome del manifest", + "Choose a name for the manifest": "Scegli un nome per il manifest", + "Required": "Richiesto", + "Open installation instructions for kiota?": "Aprire le istruzioni di installazione di kiota", + "Invalid generation type": "Tipo di generazione invalido", + "Yes, override it": "Si, sovrascrivi", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Prima di aggiungere una nuova descrizione di API, considera che le tue modifiche e la selezione corrente andranno persi", + "Cancel": "Cancella", + "Do you want to remove this API description?": "Vuoi rimuovere questa descrizione API ?", + "Please save the workspace.json file before re-generation.": "Per favore, salva il file workspace.json prima di rigenerare", + "OK": "Ok", + "Generating manifest...": "Generando il manifest...", + "Generating plugin...": "Generando il plugin...", + "Re-generating client...": "Ri-generando il client...", + "Re-generating plugin...": "Ri-generando il plugin...", + "Please migrate your API clients to Kiota workspace.":"Per favore effettua la migrazione dei tuoi client API al workspace Kiota.", + "Remind me later":"Ricordamelo dopo", + "Migrating your API clients...":"Migrazione client API in corso...", + "Migration completed, but no changes were detected.":"Migrazione completa, nessuna modifica rilevata.", + "Migration failed":"Migrazione fallita", + "API clients migrated successfully!":"Client API migrati con successo!", + "Could not determine the workspace folder.": "Impossibile determinare la cartella di lavoro." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.ja.json b/vscode/microsoft-kiota/l10n/bundle.l10n.ja.json index c4a9f9503a..7aac628a2d 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.ja.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.ja.json @@ -29,7 +29,6 @@ "Generating client...": "クライアントを生成中...", "Updating clients...": "クライアントを更新中...", "Loading...": "読み込み中...", - "Pick a lock file": "ロックファイルを選択", "Open a lock file": "ロックファイルを開く", "Filter the API description": "API仕様書をフィルタ", "Enter a filter": "フィルタを入力", @@ -39,5 +38,44 @@ "Invalid URL, please check the documentation for the supported URLs": "URLが無効です。サポートされているURLについてはドキュメントを確認してください", "No content found in the clipboard": "クリップボードの内容が空です", "Invalid content found in the clipboard": "クリップボードの内容が無効です", - "Select an API manifest key": "APIマニフェストキーを選択" + "Select an API manifest key": "APIマニフェストキーを選択", + "Edit Paths":"パスを編集", + "Re-generate": "再生成", + "Add an API description": "API仕様書を追加", + "Search or paste a path to an API description": "API仕様書のパスを検索または貼り付け", + "Generate a plugin": "プラグインを生成", + "Generate an API manifest": "APIマニフェストを生成", + "What do you want to generate?": "何を生成しますか?", + "Select an option": "オプションを選択", + "class": "クラス", + "namespace": "名前空間", + "output directory": "出力ディレクトリ", + "language": "言語", + "Create a new API client": "新しいAPIクライアントを作成", + "Create a new plugin": "新しいプラグインを作成", + "Create a new manifest": "新しいマニフェストを作成", + "plugin name:": "プラグイン名", + "Choose a name for the plugin": "プラグインの名前を選択", + "Choose a plugin type": "プラグインのタイプを選択", + "manifest name": "マニフェスト名", + "Choose a name for the manifest": "マニフェストの名前を選択", + "Required": "必須", + "Invalid generation type": "無効な生成タイプ", + "Yes, override it": "はい、オーバーライドします", + "Before adding a new API description, consider that your changes and current selection will be lost.": "新しい API の説明を追加する前に、変更内容と現在の選択内容が失われることを考慮してください。", + "Cancel": "キャンセル", + "Do you want to remove this API description?": "この API の説明を削除しますか?", + "Please save the workspace.json file before re-generation.": "再生成前にworkspace.jsonファイルを保存してください", + "OK": "OK", + "Generating manifest...": "マニフェストを生成中...", + "Generating plugin...": "プラグインを生成中...", + "Re-generating client...": "クライアントを再生成中...", + "Re-generating plugin...": "プラグインを再生成中...", + "Please migrate your API clients to Kiota workspace.":"API クライアントを Kiota ワークスペースに移行してください。", + "Remind me later":"後でリマインド", + "Migrating your API clients...":"APIクライアントを移行中...", + "Migration completed, but no changes were detected.":"移行が完了しましたが、変更は検出されませんでした。", + "Migration failed":"移行に失敗しました", + "Api clients migrated successfully!":"APIクライアントが正常に移行されました!", + "Could not determine the workspace folder.": "ワークスペースフォルダを特定できませんでした。" } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.pl.json b/vscode/microsoft-kiota/l10n/bundle.l10n.pl.json index 734da9d9b2..f27c918f25 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.pl.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.pl.json @@ -28,7 +28,6 @@ "Generating client...": "Generowanie klienta...", "Updating clients...": "Aktualizowanie klientów...", "Loading...": "Ładowanie...", - "Pick a lock file": "Wybierz plik lock", "Open a lock file": "Otwórz plik lock", "Filter the API description": "Filtruj opis API", "Enter a filter": "Wprowadź filtr", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "Nieprawidłowy adres URL, sprawdź dokumentację żeby dowiedzieć się jakie są obsługiwane adresy URL", "No content found in the clipboard": "Nie znaleziono zawartości w schowku", "Invalid content found in the clipboard": "Znaleziono nieprawidłową zawartość w schowku", - "Select an API manifest key": "Wybierz klucz manifestu API" -} \ No newline at end of file + "Select an API manifest key": "Wybierz klucz manifestu API", + "Edit Paths":"Edytuj ścieżki", + "Re-generate": "Wygeneruj ponownie", + "Add an API description": "Dodaj opis API", + "Search or paste a path to an API description": "Wyszukaj lub wklej ścieżkę do opisu API", + "Generate a plugin": "Wygeneruj wtyczkę ", + "Generate an API manifest": "Wygeneruj manifest API ", + "What do you want to generate?": "Co chcesz wygenerować? ", + "Select an option": "Wybierz opcję", + "class": "klasa", + "namespace": "przestrzeń nazw", + "output directory": "katalog wyjściowy", + "language": "język", + "Create a new API client": "Utwórz nowego klienta API ", + "Create a new plugin": "Utwórz nową wtyczkę", + "Create a new manifest": "Utwórz nowy manifest", + "plugin name:": "nazwa wtyczki", + "Choose a name for the plugin": "Wybierz nazwę dla wtyczki", + "Choose a plugin type": "Wybierz typ wtyczki", + "manifest name": "nazwa manifestu", + "Choose a name for the manifest": "Wybierz nazwę dla manifestu", + "Required": "Wymagane", + "Open installation instructions for kiota?": "Otwórz instrukcje instalacji kiota?", + "Invalid generation type": "Nieprawidłowy typ generacji", + "Yes, override it": "Tak, nadpisz", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Przed dodaniem nowego opisu API, rozważ, że Twoje zmiany i bieżący wybór zostaną utracone.", + "Cancel": "Anuluj", + "Do you want to remove this API description?": "Czy chcesz usunąć ten opis API?", + "Please save the workspace.json file before re-generation.": "Proszę zapisz plik workspace.json przed ponowną generacją.", + "OK": "OK", + "Generating manifest...": "Generowanie manifestu...", + "Generating plugin...": "Generowanie wtyczki", + "Re-generating client...": "Ponowne generowanie klienta...", + "Re-generating plugin...": "Ponowne generowanie wtyczki...", + "Please migrate your API clients to Kiota workspace.":"Proszę przenieść swoich klientów API do przestrzeni roboczej Kiota.", + "Remind me later":"Przypomnij mi później.", + "Migrating your API clients...":"Przenoszenie klientów API...", + "Migration completed, but no changes were detected.":"Migracja zakończona, ale nie wykryto żadnych zmian.", + "Migration failed":"Migracja nie powiodła się.", + "API clients migrated successfully!":"Klienci API zostali pomyślnie przeniesieni!", + "Could not determine the workspace folder.": "Nie można określić folderu przestrzeni roboczej." +} diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.pt.json b/vscode/microsoft-kiota/l10n/bundle.l10n.pt.json index 16ff82a061..3013f166fc 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.pt.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.pt.json @@ -28,7 +28,6 @@ "Generating client...": "Gerando o cliente...", "Updating clients...": "Atualizando os clientes...", "Loading...": "Carregando...", - "Pick a lock file": "Selecionar um arquivo lock", "Open a lock file": "Abrir um arquivo lock", "Filter the API description": "Filtrar descrição da API", "Enter a filter": "Adicionar um filtro", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "URL inválida, por favor, confira a documentação de URLs compatíveis", "No content found in the clipboard": "Nenhum conteúdo encontrado na área de transferência", "Invalid content found in the clipboard": "Conteúdo inváido na área de transferência", - "Select an API manifest key": "Selecione uma chave para um manifesto de API" + "Select an API manifest key": "Selecione uma chave para um manifesto de API", + "Edit Paths":"Modificar endpoints", + "Re-generate": "Gerar novamente", + "Add an API description": "Adicione a descrição de uma API", + "Search or paste a path to an API description": "Busque ou cole o caminho para uma descrição de API", + "Generate a plugin": "Gerar um plugin ", + "Generate an API manifest": "Gerar um API manifest", + "What do you want to generate?": "O que você quer gerar?", + "Select an option": "Selecione uma opção ", + "class": "classe", + "namespace": "namespace", + "output directory": "Diretório de destino", + "language": "linguagem", + "Create a new API client": "Criar um novo cliente de API", + "Create a new plugin": "Criar um novo plugin ", + "Create a new manifest": "Criar um novo manifesto", + "plugin name:": "Nome do plugin", + "Choose a name for the plugin": "Escolha um nome para o plugin", + "Choose a plugin type": "Escolha o tipo do plugin", + "manifest name": "nome do manifesto", + "Choose a name for the manifest": "Escolha um nome para o manifesto", + "Required": "Obrigatório ", + "Open installation instructions for kiota?": "Abrir as instruções de instalação do Kiota?", + "Invalid generation type": "Tipo de geração inválido ", + "Yes, override it": "Sim, substituir", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Antes de adicionar uma nova descrição de API, considere que as alterações e a seleção atual será perdida.", + "Cancel": "Cancela", + "Do you want to remove this API description?": "Você quer remover a descrição dessa API?", + "Please save the workspace.json file before re-generation.": "Por favor, salve o arquivo workspace.json antes de gerar novamente.", + "OK": "Ok", + "Generating manifest...": "Gerando o manifesto...", + "Generating plugin...": "Gerando o plugin...", + "Re-generating client...": "Regerando o cliente...", + "Re-generating plugin...": "Regerando o plugin...", + "Please migrate your API clients to Kiota workspace.":"Por favor, migre os seus clientes de API para Kiota workspace.", + "Remind me later":"Me lembre mais tarde", + "Migrating your API clients...":"Migrando os seus clientes de API...", + "Migration completed, but no changes were detected.":"Migração concluída. Nenhuma mudança foi realizada.", + "Migration failed":"A migração falhou", + "API clients migrated successfully!":"Clientes de APIs migrados com sucesso!", + "Could not determine the workspace folder.": "Não foi possível determinar a pasta de trabalho." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.ru.json b/vscode/microsoft-kiota/l10n/bundle.l10n.ru.json index 3becda22a8..2bd666428b 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.ru.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.ru.json @@ -27,7 +27,6 @@ "Generating client...": "Генерирование клиента...", "Updating clients...": "Обновление клиентов...", "Loading...": "Загрузка...", - "Pick a lock file": "Выбрать файл блокировки", "Open a lock file": "Открыть файл блокировки", "Filter the API description": "Отфильтровать описание API", "Enter a filter": "Ввести фильтр", @@ -37,5 +36,45 @@ "Invalid URL, please check the documentation for the supported URLs": "Неверный URL, пожалуйста, проверьте документацию на поддерживаемые URL", "No content found in the clipboard": "В буфере обмена нет содержимого", "Invalid content found in the clipboard": "В буфере обмена обнаружено недопустимое содержимое", - "Select an API manifest key": "Выберите ключ манифеста API для редактирования" + "Select an API manifest key": "Выберите ключ манифеста API для редактирования", + "Edit Paths":"Редактировать пути", + "Re-generate": "Перегенерировать", + "Add an API description": "Добавить описание API", + "Search or paste a path to an API description": "", + "Generate a plugin": "", + "Generate an API manifest": "", + "What do you want to generate?": "", + "Select an option": "Выбрать вариант", + "class": "класс", + "namespace": "пространство имен", + "output directory": "директория для вывода", + "language": "язык", + "Create a new API client": "", + "Create a new plugin": "", + "Create a new manifest": "Создать новый манифест", + "plugin name:": "имя плагина", + "Choose a name for the plugin": "Выберите имя для плагина", + "Choose a plugin type": "Выберите тип плагина", + "manifest name": "имя манифеста", + "Choose a name for the manifest": "Выберите имя для манифеста", + "Required": "Обязательно", + "Open installation instructions for kiota?": "Открыть инструкцию по установке Kiota?", + "Invalid generation type": "Неверный тип генерации", + "Yes, override it": "Да, перезаписать", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Прежде чем добавить новое описание API, учтите, что ваши изменения и текущий выбор будут потеряны.", + "Cancel": "Отмена", + "Do you want to remove this API description?": "", + "Please save the workspace.json file before re-generation.": "Пожалуйста, сохраните файл workspace.json перед перегенерацией.", + "OK": "OK", + "Generating manifest...": "Генерация манифеста...", + "Generating plugin...": "Генерация плагина...", + "Re-generating client...": "Перегенерация клиента...", + "Re-generating plugin...": "Перегенерация плагина...", + "Please migrate your API clients to Kiota workspace.":"Пожалуйста, перенесите ваши клиенты API в рабочее пространство Kiota.", + "Remind me later":"Напомнить позже", + "Migrating your API clients...":"Миграция ваших клиентов API...", + "Migration completed, but no changes were detected.":"Миграция завершена, но изменения не обнаружены.", + "Migration failed":"Миграция не удалась", + "API clients migrated successfully!" : "Клиенты API успешно перенесены!", + "Could not determine the workspace folder.": "Не удалось определить папку рабочего пространства." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.sw.json b/vscode/microsoft-kiota/l10n/bundle.l10n.sw.json index c42a14f1f8..b743713ed4 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.sw.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.sw.json @@ -28,7 +28,6 @@ "Generating client...": "Inatengeneza mteja...", "Updating clients...": "Inasasisha wateja...", "Loading...": "Inapakia...", - "Pick a lock file": "Chagua faili ya kufunga", "Open a lock file": "Fungua faili ya kufunga", "Filter the API description": "Chuja maelezo ya API", "Enter a filter": "Ingiza kichujio", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "URL batili, tafadhali angalia nyaraka kupata URL zinazotumika", "No content found in the clipboard": "Hakuna maudhui yaliyopatikana katika eneo la kunakili", "Invalid content found in the clipboard": "Maudhui batili yamepatikana katika eneo la kunakili", - "Select an API manifest key": "Chagua funguo ya dhahiri ya API" + "Select an API manifest key": "Chagua funguo ya dhahiri ya API", + "Edit Paths":"Hariri njia", + "Re-generate": "Tengeneza upya", + "Add an API description": "Ongeza maelezo ya API", + "Search or paste a path to an API description": "Tafuta au bandika njia ya maelezo ya API", + "Generate a plugin": "Tengeneza programu-jalizi", + "Generate an API manifest": "Tengeneza dhahiri ya API", + "What do you want to generate?": "Unataka kutengeneza nini?", + "Select an option": "Chagua chaguo", + "class": "darasa", + "namespace": "nafasijina", + "output directory": "eneo ya pato", + "language": "lugha", + "Create a new API client": "Tengeneza mteja mpya wa API", + "Create a new plugin": "Tengeneza programu-jalizi mpya", + "Create a new manifest": "Tengeneza dhariri mpya", + "plugin name:": "Jina ya programu-jalizi", + "Choose a name for the plugin": "Changua jina ya programu-jalizi", + "Choose a plugin type": "Chagua aina ya programu-jalizi", + "manifest name": "jina ya dhariri", + "Choose a name for the manifest": "Chagua jina ya dhariri ", + "Required": "Inahitajika", + "Open installation instructions for kiota?": "Je, ungetaka kufungua maagizo ya usakinishaji ya Kiota?", + "Invalid generation type": "Aina ya kutengeneza ni batili", + "Yes, override it": "Ndio, ipuuze", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Kabla ya kuongeza maelezo mapya ya API, fikiria kuwa mabadiliko yako na uteuzi wa sasa utapotea.", + "Cancel": "Katisha", + "Do you want to remove this API description?": "Ungetaka kuondoa maelezo haya ya API?", + "Please save the workspace.json file before re-generation.": "Tafadhali hifadhi faili ya workspace.json kabla ya kutengeneza upya.", + "OK": "Sawa", + "Generating manifest...": "Inatengeneza dhariri..", + "Generating plugin...": "Inatengeneza programu-jalizi...", + "Re-generating client...": "Inatengeneza mteja upya...", + "Re-generating plugin...": "Inatengeneza programu-jalizi upya ...", + "Please migrate your API clients to Kiota workspace." : "Tafadhali hamisha wateja wako wa API kwenye nafasi ya kazi ya Kiota.", + "Remind me later": "Nikumbushe baadaye", + "Migrating your API clients..." : "Inahamisha wateja wako wa API...", + "Migration completed, but no changes were detected." : "Uhamisho umekamilika, lakini hakuna mabadiliko yaligunduliwa.", + "Migration failed" : "Uhamisho ulishindikana", + "API client migrateds successfully!" : "Wateja wa API wamehamishwa kwa mafanikio!", + "Could not determine the workspace folder.": "Haiwezekani kubaini folda ya kazi." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.tr.json b/vscode/microsoft-kiota/l10n/bundle.l10n.tr.json index 84f00f97e9..0df5216638 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.tr.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.tr.json @@ -28,7 +28,6 @@ "Generating client...": "İstemci oluşturuluyor...", "Updating clients...": "İstemciler güncelleniyor...", "Loading...": "Yükleniyor...", - "Pick a lock file": "Bir kilit dosyası seçin", "Open a lock file": "Bir kilit dosyası açın", "Filter the API description": "API açıklamasını filtreleyin", "Enter a filter": "Filtre girin", @@ -38,5 +37,45 @@ "Invalid URL, please check the documentation for the supported URLs": "Geçersiz URL, lütfen desteklenen URL'ler için dokümanları kontrol edin", "No content found in the clipboard": "Panoda içerik bulunamadı", "Invalid content found in the clipboard": "Panoda geçersiz içerik bulundu", - "Select an API manifest key": "Bir API manifest anahtarı seçin" + "Select an API manifest key": "Bir API manifest anahtarı seçin", + "Edit Paths":"Yolları Düzenle", + "Re-generate": "Yeniden oluştur", + "Add an API description": "API açıklaması ekle", + "Search or paste a path to an API description": "API açıklaması için bir yol arayın veya yapıştırın", + "Generate a plugin": "Bir eklenti oluştur", + "Generate an API manifest": "Bir API manifesti oluştur", + "What do you want to generate?": "Ne oluşturmak istiyorsunuz?", + "Select an option": "Bir seçenek seçin", + "class": "sınıf", + "namespace": "isim alanı", + "output directory": "çıktı dizini", + "language": "dil", + "Create a new API client": "Yeni bir API istemcisi oluştur", + "Create a new plugin": "Yeni bir eklenti oluştur", + "Create a new manifest": "Yeni bir manifest oluştur", + "plugin name:": "Eklenti adı", + "Choose a name for the plugin": "Eklenti için bir ad seçin", + "Choose a plugin type": "Eklenti türünü seçin", + "manifest name": "Manifest adı", + "Choose a name for the manifest": "Manifest için bir ad seçin", + "Required": "Gerekli", + "Open installation instructions for kiota?": "Kiota için kurulum talimatlarını açmak ister misiniz?", + "Invalid generation type": "Geçersiz nesil tipi", + "Yes, override it": "Evet, geçersiz kıl.", + "Before adding a new API description, consider that your changes and current selection will be lost.": "Yeni bir API açıklaması eklemeye başlamadan önce, değişikliklerinizin ve mevcut seçiminizin kaybolacağını düşünün.", + "Cancel": "İptal", + "Do you want to remove this API description?": "Bu API açıklamasını kaldırmak istiyor musunuz?", + "Please save the workspace.json file before re-generation.": "Yeniden oluşturmadan önce workspace.json dosyasını kaydedin.", + "OK": "Tamam", + "Generating manifest...": "Manifest oluşturuluyor...", + "Generating plugin...": "Eklenti oluşturuluyor...", + "Re-generating client...": "İstemci yeniden oluşturuluyor...", + "Re-generating plugin...": "Eklenti yeniden oluşturuluyor...", + "Please migrate your API clients to Kiota workspace.":"Lütfen API istemcilerinizi Kiota çalışma alanına taşıyın.", + "Remind me later":"Bana daha sonra hatırlat.", + "Migrating your API clients...":"API istemcileriniz taşınıyor...", + "Migration completed, but no changes were detected.":"Taşıma tamamlandı, ancak herhangi bir değişiklik tespit edilmedi.", + "Migration failed":"Taşıma başarısız oldu.", + "API clients migrated successfully!":"API istemcileri başarıyla taşındı!", + "Could not determine the workspace folder.": "Çalışma alanı klasörü belirlenemedi." } diff --git a/vscode/microsoft-kiota/l10n/bundle.l10n.zh-cn.json b/vscode/microsoft-kiota/l10n/bundle.l10n.zh-cn.json index 4a24b4c5c0..a7eaff48df 100644 --- a/vscode/microsoft-kiota/l10n/bundle.l10n.zh-cn.json +++ b/vscode/microsoft-kiota/l10n/bundle.l10n.zh-cn.json @@ -27,7 +27,6 @@ "Generating client...": "正在生成客户端...", "Updating clients...": "正在更新客户端...", "Loading...": "加载中...", - "Pick a lock file": "请选择一个锁定文件", "Open a lock file": "请打开一个锁定文件", "Filter the API description": "筛选API描述", "Enter a filter": "输入一个筛选项", @@ -37,5 +36,45 @@ "Invalid URL, please check the documentation for the supported URLs": "无效路径,请检查在文档中寻找支持的路径", "No content found in the clipboard": "剪贴板空白", "Invalid content found in the clipboard": "剪贴板内容无效", - "Select an API manifest key": "选择API清单访问密钥" + "Select an API manifest key": "选择API清单访问密钥", + "Edit Paths":"编辑路径", + "Re-generate": "重新生成", + "Add an API description": "添加 API 描述", + "Search or paste a path to an API description": "搜索或粘贴 API 描述的路径", + "Generate a plugin": "生成插件", + "Generate an API manifest": "生成 API 清单", + "What do you want to generate?": "您要生成什么", + "Select an option": "选择一个选项", + "class": "类", + "namespace": "命名空间", + "output directory": "输出目录", + "language": "语言", + "Create a new API client": "创建新的 API 客户端", + "Create a new plugin": "创建一个新插件", + "Create a new manifest": "创建新清单", + "plugin name:": "插件名称", + "Choose a name for the plugin:": "为插件选择一个名称", + "Choose a plugin type": "选择插件类型", + "manifest name": "清单名", + "Choose a name for the manifest": "选择清单的名称", + "Required": "必填", + "Open installation instructions for kiota?": "打开 kiota 的安装说明?", + "Invalid generation type": "无效的生成类型", + "Yes, override it": "是的,覆盖它", + "Before adding a new API description, consider that your changes and current selection will be lost.": "在添加新的 API 描述之前,请考虑您的更改和当前选择将丢失。", + "Cancel": "取消", + "Do you want to remove this API description?": "是否要删除此 API 描述?", + "Please save the workspace.json file before re-generation.": "请在重新生成之前保存workspace.json文件", + "OK": "OK", + "Generating manifest...": "正在生成清单...", + "Generating plugin...": "正在生成插件...", + "Re-generating client...": "重新生成客户端...", + "Re-generating plugin...": "正在重新生成插件...", + "Please migrate your API clients to Kiota workspace.":"请将您的 API 客户端迁移到 Kiota 工作区", + "Remind me later":"稍后提醒我", + "Migrating your API clients...":"正在迁移您的 API 客户端...", + "Migration completed, but no changes were detected.":"迁移已完成,但未检测到任何更改", + "Migration failed":"迁移失败", + "API clients migrated successfully!":"Api客户端迁移成功!", + "Could not determine the workspace folder.": "无法确定工作区文件夹" } diff --git a/vscode/microsoft-kiota/package-lock.json b/vscode/microsoft-kiota/package-lock.json index dcb5071df9..47c2f09de9 100644 --- a/vscode/microsoft-kiota/package-lock.json +++ b/vscode/microsoft-kiota/package-lock.json @@ -1,12 +1,12 @@ { "name": "kiota", - "version": "1.12.100000001", + "version": "1.18.100000001", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kiota", - "version": "1.12.100000001", + "version": "1.18.100000001", "dependencies": { "@vscode/extension-telemetry": "^0.9.7", "@vscode/l10n": "^0.0.18", diff --git a/vscode/microsoft-kiota/package.json b/vscode/microsoft-kiota/package.json index fe8adee60f..078e6552b0 100644 --- a/vscode/microsoft-kiota/package.json +++ b/vscode/microsoft-kiota/package.json @@ -3,8 +3,8 @@ "displayName": "Microsoft Kiota", "publisher": "ms-graph", "description": "Client generator for HTTP REST APIs described by OpenAPI which helps eliminate the need to take a dependency on a different API client for every API that you need to call, as well as limiting the generation to the exact API surface area you're interested in, thanks to a filtering capability.", - "version": "1.12.100000001", - "kiotaVersion": "1.12.0", + "version": "1.18.100000001", + "kiotaVersion": "1.17.0", "telemetryInstrumentationKey": "4c6357e0-daf9-42b5-bdfb-67878f8957b5", "icon": "images/logo.png", "engines": { @@ -190,12 +190,6 @@ } } }, - "viewsWelcome": [ - { - "view": "kiota.openApiExplorer", - "contents": "%kiota.openApiExplorer.welcome%" - } - ], "viewsContainers": { "activitybar": [ { @@ -216,9 +210,11 @@ "kiota-openapi-explorer": [ { "id": "kiota.openApiExplorer", - "name": "%kiota.openApiExplorer.name%", - "icon": "media/logo.svg", - "contextualTitle": "%kiota.openApiExplorer.contextualTitle%" + "name": "%kiota.openApiExplorer.name%" + }, + { + "id": "kiota.workspace", + "name": "%kiota.workspace.name%" } ], "kiota-dependencies-info": [ @@ -237,60 +233,65 @@ { "command": "kiota.selectLock", "group": "2_kiota@1", - "when": "resourceLangId == json && resourceFilename =~ /kiota-lock\\.json$/" + "when": "resourceLangId == json && resourceFilename =~ /workspace\\.json$/" + }, + { + "command": "kiota.migrateFromLockFile", + "when": "resourceExtname == .json && resourceFilename == kiota-lock.json", + "group": "navigation" } ], "view/title": [ { - "command": "kiota.openApiExplorer.openDescription", - "when": "view == kiota.openApiExplorer", - "group": "navigation@2" - }, - { - "command": "kiota.searchApiDescription", + "command": "kiota.openApiExplorer.searchOrOpenApiDescription", "when": "view == kiota.openApiExplorer", "group": "navigation@1" }, { "command": "kiota.openApiExplorer.filterDescription", "when": "view == kiota.openApiExplorer", - "group": "navigation@3" + "group": "navigation@2" }, { "command": "kiota.openApiExplorer.generateClient", "when": "view == kiota.openApiExplorer", - "group": "navigation@4" + "group": "navigation@3" }, { - "command": "kiota.openApiExplorer.closeDescription", + "command": "kiota.openApiExplorer.regenerateButton", "when": "view == kiota.openApiExplorer", - "group": "navigation@5" + "group": "navigation@4" } ], "view/item/context": [ + { + "command": "kiota.openApiExplorer.closeDescription", + "when": "view == kiota.openApiExplorer && viewItem == apiTitle", + "group": "inline@6" + }, { "command": "kiota.openApiExplorer.openDocumentationPage", - "when": "view == kiota.openApiExplorer && (viewItem || false)", + "when": "view == kiota.openApiExplorer && (viewItem == documentationUrl)", "group": "inline@1" }, { "command": "kiota.openApiExplorer.addToSelectedEndpoints", - "when": "view == kiota.openApiExplorer", + "when": "view == kiota.openApiExplorer && viewItem != apiTitle && viewItem != clientNameOrPluginName", "group": "inline@2" }, { "command": "kiota.openApiExplorer.addAllToSelectedEndpoints", - "when": "view == kiota.openApiExplorer", + "when": "view == kiota.openApiExplorer && viewItem != clientNameOrPluginName", "group": "inline@4" }, { "command": "kiota.openApiExplorer.removeFromSelectedEndpoints", - "when": "view == kiota.openApiExplorer", + "when": "view == kiota.openApiExplorer && viewItem != apiTitle && viewItem != clientNameOrPluginName", "group": "inline@3" }, { "command": "kiota.openApiExplorer.removeAllFromSelectedEndpoints", - "when": "view == kiota.openApiExplorer", + "when": "view == kiota.openApiExplorer && viewItem != clientNameOrPluginName", "group": "inline@5" } ], @@ -319,19 +320,16 @@ "command": "kiota.openApiExplorer.removeAllFromSelectedEndpoints", "when": "false" } + ], + "editor/context": [ + { + "command": "kiota.migrateFromLockFile", + "when": "resourceExtname == .json && resourceFilename == kiota-lock.json", + "group": "navigation" + } ] }, "commands": [ - { - "command": "kiota.openApiExplorer.pasteManifest", - "category": "Kiota", - "title": "%kiota.openApiExplorer.pasteManifest.title%" - }, - { - "command": "kiota.openApiExplorer.openManifestPath", - "category": "Kiota", - "title": "%kiota.openApiExplorer.openManifestPath.title%" - }, { "command": "kiota.selectLock", "category": "Kiota", @@ -353,19 +351,22 @@ "command": "kiota.openApiExplorer.generateClient", "category": "Kiota", "title": "%kiota.openApiExplorer.generateClient.title%", - "icon": "$(play)" + "enablement": "kiota.openApiExplorer.showIcons", + "icon": "$(run-all)" }, { - "command": "kiota.openApiExplorer.filterDescription", + "command": "kiota.openApiExplorer.regenerateButton", "category": "Kiota", - "title": "%kiota.openApiExplorer.filterDescription.title%", - "icon": "$(filter)" + "title": "%kiota.openApiExplorer.regenerateButton.title%", + "enablement": "kiota.openApiExplorer.showRegenerateIcon", + "icon": "$(debug-rerun)" }, { - "command": "kiota.searchApiDescription", + "command": "kiota.openApiExplorer.filterDescription", "category": "Kiota", - "title": "%kiota.searchApiDescription.title%", - "icon": "$(search)" + "title": "%kiota.openApiExplorer.filterDescription.title%", + "enablement": "kiota.openApiExplorer.showIcons", + "icon": "$(filter)" }, { "command": "kiota.openApiExplorer.addToSelectedEndpoints", @@ -401,13 +402,48 @@ "command": "kiota.openApiExplorer.closeDescription", "category": "Kiota", "title": "%kiota.openApiExplorer.closeDescription.title%", - "icon": "$(close)" + "icon": "$(trash)" }, { - "command": "kiota.openApiExplorer.openDescription", + "command": "kiota.openApiExplorer.searchOrOpenApiDescription", "category": "Kiota", "title": "%kiota.openApiExplorer.openDescription.title%", - "icon": "$(go-to-file)" + "icon": "$(new-file)" + }, + { + "command": "kiota.workspace.openWorkspaceFile", + "title": "%kiota.openApiExplorer.openFile.title%" + }, + { + "command": "kiota.editPaths", + "title": "%kiota.openApiExplorer.editPaths.title%" + }, + { + "command": "kiota.regenerate", + "title": "%kiota.openApiExplorer.regenerateButton.title%" + }, + { + "command": "kiota.workspace.refresh", + "title": "%kiota.openApiExplorer.refresh.title%" + }, + { + "command": "kiota.migrateFromLockFile", + "title": "%kiota.migrateClients.title%" + } + + ], + "languages": [ + { + "id": "json", + "extensions": [ + ".json" + ] + } + ], + "codeLensProviders": [ + { + "language": "json", + "provideCodeLenses": true } ] }, @@ -451,23 +487,23 @@ "runtimeDependencies": [ { "platformId": "win-x64", - "sha256": "04884ED264534CCE1708F0377809A98BFBE73F1B916432B71845CFF426B4E15D" + "sha256": "103A685302D9F3DC6D87B446414DDE7099F36749959AD3B31506AA306E6106B7" }, { "platformId": "win-x86", - "sha256": "9324A3B58889B0DD123B478608E6A59FED3147B3268C4EF37F172BC9517B1233" + "sha256": "C79D2108129C3187DE14320478AE9588DF100FF5E37270BEBACFBBDC2EF9AEED" }, { "platformId": "linux-x64", - "sha256": "C093782E42DFA98574A1503D27F661F54F1C8CA92B66F6ED7B9DF475447E1769" + "sha256": "C8F518D723B8ADFCE699E1E4E03BB3E03A300D9BA4F10558351634396EF3AA1E" }, { "platformId": "osx-x64", - "sha256": "7911E277474EFF71D00C9983A9F3E43460F5C3C3FBB565CFE069854BA4069FCD" + "sha256": "8EEFB9BF46871E8830BC59F3A52B0C2F20643F0C094611539A00548C70A2223A" }, { "platformId": "osx-arm64", - "sha256": "032AFBCF63FFF1C21215277E5EAFDD1909E1EFE5213B15F52ED4BBBDF3695C0A" + "sha256": "5FE16C08C749ABEB286520A7A2C9E7F62BE4102765486211433CAE6E8252E44F" } ] } diff --git a/vscode/microsoft-kiota/package.nls.ar.json b/vscode/microsoft-kiota/package.nls.ar.json index a88a2ef3eb..c175ffc30d 100644 --- a/vscode/microsoft-kiota/package.nls.ar.json +++ b/vscode/microsoft-kiota/package.nls.ar.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "مستكشف Kiota OpenAPI", "kiota.openApiExplorer.contextualTitle": "مستكشف OpenAPI", "kiota-dependencies-info.panel.title": "معلومات حول تبعيات Kiota", - "kiota-openapi-explorer.activitybar.title": "مستكشف Kiota OpenAPI", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "اختر ملف القفل لمستكشف الAPI", "kiota.updateClients.title": "حدث عملاء الAPI في مساحة العمل الحالية", "kiota.openApiExplorer.generateClient.title": "انشاء عميل الAPI", - "kiota.searchApiDescription.title": "ابحث عن وصف API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "اضف", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "احذف", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "اضف الكل", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "احذف الكل", "kiota.openApiExplorer.closeDescription.title": "اغلق وصف API", "kiota.openApiExplorer.openDescription.title": "افتح وصف API", - "kiota.openApiExplorer.welcome": "لم يتم اختيار وصف API\n[ابحث](command:kiota.searchApiDescription)\n[افتح وصف API](command:kiota.openApiExplorer.openDescription)\n[افتح البيان](command:command:kiota.openApiExplorer.openManifestPath)\n[الصق البيان](command:kiota.openApiExplorer.pasteManifest)\n[اختر ملف](command:kiota.searchLock)", "kiota.searchLock.title": "ابحث عن ملف قفل", "kiota.openApiExplorer.filterDescription.title": "قم بتصفية وصف API", "kiota.openApiExplorer.openDocumentationPage.title": "افتح صفحة الوثائق", - "kiota.openApiExplorer.openManifestPath.title": "افتح بيان واجهة برمجة التطبيقات", - "kiota.openApiExplorer.pasteManifest.title": "الصق بيان واجهة برمجة التطبيقات", "kiota.generate.backingStore.description": "تمكين مخزن الدعم للنماذج", "kiota.generate.excludeBackwardCompatible.description": "يستبعد الأصول المتوافقة مع الإصدارات السابقة والمتقادمة من النتيجة التي تم إنشاؤها. ينبغي أن تستخدم للعملاء الجدد", "kiota.cleanOutput.description": "يزيل كافة الملفات من دليل الإخراج قبل إنشاء ملفات التعليمات البرمجية", @@ -29,5 +25,9 @@ "kiota.generate.serializer.description": "أسماء الفئات المؤهلة بالكامل للمتسلسلات", "kiota.generate.deserializer.description": "أسماء الفئات المؤهلة بالكامل لإلغاء التسلسل", "kiota.generate.structuredMimeTypes.description": "أنواع MIME والتفضيلات المستخدمة لإنشاء نماذج البيانات المنظمة. وفقًا لـ RFC9110، قم بقبول تدوين الرأس.", - "kiota.generate.includeAdditionalData.description": "سيتم تضمين خاصية 'Additional Data' للنماذج" + "kiota.generate.includeAdditionalData.description": "سيتم تضمين خاصية 'Additional Data' للنماذج", + "kiota.workspace.name": "مساحة العمل", + "kiota.openApiExplorer.regenerateButton.title": "إعادة توليد", + "kiota.openApiExplorer.editPaths.title": "تحرير المسارات", + "kiota.migrateClients.title": "ترحيل عملاء الAPI" } diff --git a/vscode/microsoft-kiota/package.nls.cs.json b/vscode/microsoft-kiota/package.nls.cs.json index 6809d58fe4..f010aeb6f0 100644 --- a/vscode/microsoft-kiota/package.nls.cs.json +++ b/vscode/microsoft-kiota/package.nls.cs.json @@ -8,19 +8,15 @@ "kiota.selectLock.title": "Vyberte soubor zámku pro průzkumníka API", "kiota.updateClients.title": "Aktualizovat klienty v aktuálním pracovním prostoru", "kiota.openApiExplorer.generateClient.title": "Vygenerovat API klienta", - "kiota.searchApiDescription.title": "Hledat popis API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Přidat", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Odebrat", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Přidat vše", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Odebrat vše", "kiota.openApiExplorer.closeDescription.title": "Zavřít popis API", "kiota.openApiExplorer.openDescription.title": "Otevřít popis API", - "kiota.openApiExplorer.welcome": "Není vybrán žádný popis API.\n[Hledat](command:kiota.searchApiDescription)\n[Otevřít popis API](command:kiota.openApiExplorer.openDescription)\n[Otevřít manifest](command:kiota.openApiExplorer.openManifestPath)\n[Vložit manifest](command:kiota.openApiExplorer.pasteManifest)\n[Vybrat soubor se zámkem](command:kiota.searchLock)", "kiota.searchLock.title": "Hledat soubor se zámkem", "kiota.openApiExplorer.filterDescription.title": "Filtrovat popis API", "kiota.openApiExplorer.openDocumentationPage.title": "Otevřít stránku dokumentace", - "kiota.openApiExplorer.openManifestPath.title": "Otevřít API manifest", - "kiota.openApiExplorer.pasteManifest.title": "Vložit API manifest", "kiota.generate.backingStore.description": "Povoluje úložiště pro modely", "kiota.generate.excludeBackwardCompatible.description": "Vylučuje zpětně kompatibilní a zastaralé prvky z vygenerovaného výsledku. Mělo by se používat pro nové klienty", "kiota.cleanOutput.description": "Odstraní všechny soubory z výstupního adresáře před generováním souborů s kódem", @@ -31,5 +27,7 @@ "kiota.generate.structuredMimeTypes.description": "MIME typy a preference pro generování strukturovaných datových modelů. Podle notace Accept hlavičky dle RFC9110.", "kiota.generate.includeAdditionalData.description": "Bude zahrnuta vlastnost 'AdditionalData' pro modely", "kiota.workspace.name": "Můj pracovní prostor", - "kiota.openApiExplorer.openFile.title": "Otevřít soubor" + "kiota.openApiExplorer.regenerateButton.title": "Znovu vygenerovat", + "kiota.openApiExplorer.editPaths.title": "Upravit cesty", + "kiota.migrateClients.title": "Migrovat API klienty" } diff --git a/vscode/microsoft-kiota/package.nls.es.json b/vscode/microsoft-kiota/package.nls.es.json index 6a29c5dd5c..2265e8f1a2 100644 --- a/vscode/microsoft-kiota/package.nls.es.json +++ b/vscode/microsoft-kiota/package.nls.es.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Explorador de OpenAPI de Kiota", "kiota.openApiExplorer.contextualTitle": "Explorador de OpenAPI", "kiota-dependencies-info.panel.title": "Información sobre las dependencias de Kiota", - "kiota-openapi-explorer.activitybar.title": "Explorador de OpenAPI de Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Seleccionar archivo de bloqueo para vista en Explorador de API", "kiota.updateClients.title": "Actualizar clientes del API en este espacio de trabajo", "kiota.openApiExplorer.generateClient.title": "Generar cliente del API", - "kiota.searchApiDescription.title": "Buscar descripciones de APIs", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Agregar", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Quitar", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Agregar todo", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Quitar todo", "kiota.openApiExplorer.closeDescription.title": "Cerrar descripción del API", "kiota.openApiExplorer.openDescription.title": "Abrir descripción del API", - "kiota.openApiExplorer.welcome": "No ha seleccionado una descripción de API.\n[Buscar](command:kiota.searchApiDescription)\n[Abrir](command:kiota.openApiExplorer.openDescription)\n[Seleccionar archivo lock](command:kiota.searchLock)", "kiota.searchLock.title": "Buscar un archivo lock", "kiota.openApiExplorer.filterDescription.title": "Filtrar descripción de API", "kiota.openApiExplorer.openDocumentationPage.title": "Abrir documentación", - "kiota.openApiExplorer.openManifestPath.title": "Abrir manifesto de OpenAPI", - "kiota.openApiExplorer.pasteManifest.title": "Pegar manifesto de OpenAPI", "kiota.generate.backingStore.description": "Habilita almacenamiento de respaldo para los modelos.", "kiota.generate.excludeBackwardCompatible.description": "Excluye activos obsoletos y compatibles con anteriores versiones del resultado generado. Debe ser usado para nuevos clientes.", "kiota.cleanOutput.description": "Remueve todos los archivos del directorio producido antes de generar los archivos de código.", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "Los nombres de clase completamente calificados para serializadores", "kiota.generate.deserializer.description": "Los nombres de clase completamente calificados para deserializadores", "kiota.generate.structuredMimeTypes.description": "Las preferencias y tipos MIME para usar en la generación de modelos de data estructurados. De acuerdo con RFC9110, acepte notación de encabezado.", - "kiota.generate.includeAdditionalData.description": "Incluirá la propiedad 'AdditionalData' para modelos." + "kiota.generate.includeAdditionalData.description": "Incluirá la propiedad 'AdditionalData' para modelos.", + "kiota.workspace.name": "Mi espacio de trabajo", + "kiota.openApiExplorer.regenerateButton.title": "Re-generar", + "kiota.openApiExplorer.editPaths.title": "Editar ruta de acceso", + "kiota.openApiExplorer.refresh.title": "Actualizar", + "kiota.migrateClients.title": "Migrar clientes del API" } diff --git a/vscode/microsoft-kiota/package.nls.fr.json b/vscode/microsoft-kiota/package.nls.fr.json index 1bf8b76657..a21a66347a 100644 --- a/vscode/microsoft-kiota/package.nls.fr.json +++ b/vscode/microsoft-kiota/package.nls.fr.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Explorateur OpenAPI Kiota", "kiota.openApiExplorer.contextualTitle": "Explorateur OpenAPI", "kiota-dependencies-info.panel.title": "Informations sur les dépendances Kiota", - "kiota-openapi-explorer.activitybar.title": "Explorateur OpenAPI Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Sélectionner pour la vue explorateur d'API", "kiota.updateClients.title": "Mettre à jour les clients d'API dans l'environment courant", "kiota.openApiExplorer.generateClient.title": "Générer le client d'API", - "kiota.searchApiDescription.title": "Rechercher une description d'API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Ajouter", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Supprimer", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Tout ajouter", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Tout supprimer", "kiota.openApiExplorer.closeDescription.title": "Fermer la description d'API", "kiota.openApiExplorer.openDescription.title": "Ouvrir une description d'API", - "kiota.openApiExplorer.welcome": "Aucune description sélectionnée.\n[Rechercher](command:kiota.searchApiDescription)\n[Ouvrir une description OpenAPI](command:kiota.openApiExplorer.openDescription)\n[Ouvrir un manifeste d'API](command:command:kiota.openApiExplorer.openManifestPath)\n[Coller un manifeste d'API](command:kiota.openApiExplorer.pasteManifest)\n[Sélectionner un fichier verrou](command:kiota.searchLock)", "kiota.searchLock.title": "Rechercher un fichier verrou", "kiota.openApiExplorer.filterDescription.title": "Filtrer la description", "kiota.openApiExplorer.openDocumentationPage.title": "Ouvrir la page de documentation", - "kiota.openApiExplorer.openManifestPath.title": "Ouvrir un manifeste d'API", - "kiota.openApiExplorer.pasteManifest.title": "Coller un manifeste d'API", "kiota.generate.backingStore.description": "Active le stockage d'informations déporté pour les modèles.", "kiota.generate.excludeBackwardCompatible.description": "Exclue les éléments de compatibilité et obsolètes du résultat. Devrait être activé pour tout nouveau client.", "kiota.cleanOutput.description": "Supprime tous les fichiers du répertoire de destination avant de générer les nouveaux fichiers.", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "Le nom complet des classes de sérialisation.", "kiota.generate.deserializer.description": "Le nom complet des classes de désérialisation.", "kiota.generate.structuredMimeTypes.description": "Les types MIME et ordre de préférence à utiliser pour la génération de modèles structurés. Suit la convention décrite dans la RFC 9110 pour l'entête Accept.", - "kiota.generate.includeAdditionalData.description": "Incluera la propriété 'AdditionalData' pour les modèles générés." + "kiota.generate.includeAdditionalData.description": "Incluera la propriété 'AdditionalData' pour les modèles générés.", + "kiota.workspace.name": "Mon espace de travail", + "kiota.openApiExplorer.regenerateButton.title": "Générer de nouveau", + "kiota.openApiExplorer.editPaths.title": "Modifier les chemins", + "kiota.openApiExplorer.refresh.title": "Rafraîchir", + "kiota.migrateClients.title": "Migrer les clients d'API" } diff --git a/vscode/microsoft-kiota/package.nls.it.json b/vscode/microsoft-kiota/package.nls.it.json index f6e638b902..7f7155d26a 100644 --- a/vscode/microsoft-kiota/package.nls.it.json +++ b/vscode/microsoft-kiota/package.nls.it.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Kiota OpenAPI Explorer", "kiota.openApiExplorer.contextualTitle": "OpenAPI Explorer", "kiota-dependencies-info.panel.title": "Informazioni sulle Dipendenze di Kiota", - "kiota-openapi-explorer.activitybar.title": "Kiota OpenAPI Explorer", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Seleziona un file di lock per visualizzarlo all'interno di API Explorer", "kiota.updateClients.title": "Aggiorna i client API nel workspace corrente", "kiota.openApiExplorer.generateClient.title": "Genera un client API", - "kiota.searchApiDescription.title": "Cerca una descrizione API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Aggiungi", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Rimuovi", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Aggiungi tutti", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Rimuovi tutti", "kiota.openApiExplorer.closeDescription.title": "Chiudi la descrizione API", "kiota.openApiExplorer.openDescription.title": "Apri una descrizione API", - "kiota.openApiExplorer.welcome": "Nessuna descrizione delle API selezionata.\n[Search](command:kiota.searchApiDescription)\n[Apri una descrizione API](command:kiota.openApiExplorer.openDescription)\n[Apri un manifest](command:kiota.openApiExplorer.openManifestPath)\n[Copia un manifest](command:kiota.openApiExplorer.pasteManifest)\n[Seleziona un file di lock](command:kiota.searchLock)", "kiota.searchLock.title": "Cerca il file di lock", "kiota.openApiExplorer.filterDescription.title": "Filtra la descrizione delle API", "kiota.openApiExplorer.openDocumentationPage.title": "Apri la pagina di documentazione", - "kiota.openApiExplorer.openManifestPath.title": "Apri il manifest delle API", - "kiota.openApiExplorer.pasteManifest.title": "Copia il manifest delle API", "kiota.generate.backingStore.description": "Abilita il backing store per i modelli", "kiota.generate.excludeBackwardCompatible.description": "Esclude gli asset retrocompatibili e obsoleti dal risultato generato. Da utilizzare per i nuovi clienti", "kiota.cleanOutput.description": "Rimuove tutti i file dalla directory di output prima di generare i file di codice.", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "I nomi di classe completamente qualificati per i serializzatori", "kiota.generate.deserializer.description": "I nomi delle classi completamente qualificate per i deserializzatori", "kiota.generate.structuredMimeTypes.description": "I tipi MIME e le preferenze da utilizzare per la generazione di modelli di dati strutturati. Come riportato nella notazione RFC9110 dell'header Accept.", - "kiota.generate.includeAdditionalData.description": "Includerà la proprietà 'AdditionalData' per i modelli" + "kiota.generate.includeAdditionalData.description": "Includerà la proprietà 'AdditionalData' per i modelli", + "kiota.workspace.name": "Il mio spazio di lavoro", + "kiota.openApiExplorer.regenerateButton.title": "Rigener", + "kiota.openApiExplorer.editPaths.title": "Modifica i percorsi", + "kiota.openApiExplorer.refresh.title": "Aggiorna", + "kiota.migrateClients.title": "Migra i client API" } diff --git a/vscode/microsoft-kiota/package.nls.ja.json b/vscode/microsoft-kiota/package.nls.ja.json index 6dfc8041a8..9a6efa3282 100644 --- a/vscode/microsoft-kiota/package.nls.ja.json +++ b/vscode/microsoft-kiota/package.nls.ja.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Kiota OpenAPIエクスプローラ", "kiota.openApiExplorer.contextualTitle": "OpenAPIエクスプローラ", "kiota-dependencies-info.panel.title": "Kiota依存関係情報", - "kiota-openapi-explorer.activitybar.title": "Kiota OpenAPIエクスプローラ", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "APIエクスプローラビューのロックファイルを選択", "kiota.updateClients.title": "現在のワークスペースでAPIクライアントを更新", "kiota.openApiExplorer.generateClient.title": "APIクライアントを生成", - "kiota.searchApiDescription.title": "API仕様書を検索", "kiota.openApiExplorer.addToSelectedEndpoints.title": "追加", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "削除", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "すべて追加", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "すべて削除", "kiota.openApiExplorer.closeDescription.title": "API仕様書を閉じる", "kiota.openApiExplorer.openDescription.title": "API仕様書を開く", - "kiota.openApiExplorer.welcome": "API仕様書が選択されていません。\n[検索](command:kiota.searchApiDescription)\n[API仕様書を開く](command:kiota.openApiExplorer.openDescription)\n[マニフェストを開く](command:kiota.openApiExplorer.openManifestPath)\n[マニフェストを貼り付け](command:kiota.openApiExplorer.pasteManifest)\n[ロックファイルを選択](command:kiota.searchLock)", "kiota.searchLock.title": "ロックファイルを検索", "kiota.openApiExplorer.filterDescription.title": "API仕様書をフィルタ", "kiota.openApiExplorer.openDocumentationPage.title": "ドキュメントページを開く", - "kiota.openApiExplorer.openManifestPath.title": "APIマニフェストを開く", - "kiota.openApiExplorer.pasteManifest.title": "APIマニフェストを貼り付け", "kiota.generate.backingStore.description": "モデルのバッキングストアを有効にする", "kiota.generate.excludeBackwardCompatible.description": "生成された結果から後方互換性のある古いアセットを除外する(新規クライアントに使用)", "kiota.cleanOutput.description": "コードファイルを生成する前に出力先のディレクトリからすべてのファイルを削除する", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "シリアライザの完全修飾クラス名", "kiota.generate.deserializer.description": "デシリアライザの完全修飾クラス名", "kiota.generate.structuredMimeTypes.description": "構造化データモデル生成に使用するMIMEタイプと設定(RFC 9110のAcceptヘッダー表記)", - "kiota.generate.includeAdditionalData.description": "モデルのための“AdditionalData”プロパティを含める" + "kiota.generate.includeAdditionalData.description": "モデルのための“AdditionalData”プロパティを含める", + "kiota.workspace.name": "ワークスペース", + "kiota.openApiExplorer.regenerateButton.title": "再生成", + "kiota.openApiExplorer.editPaths.title": "パスを編集", + "kiota.openApiExplorer.refresh.title": "リフレッシュ", + "kiota.migrateClients.title": "APIクライアントを移行" } diff --git a/vscode/microsoft-kiota/package.nls.json b/vscode/microsoft-kiota/package.nls.json index b8879840bd..5c7baf619a 100644 --- a/vscode/microsoft-kiota/package.nls.json +++ b/vscode/microsoft-kiota/package.nls.json @@ -1,26 +1,22 @@ { "kiota.dependenciesInfo.name": "Kiota Dependencies Information", "kiota.dependenciesInfo.contextualTitle": "Dependencies Information", - "kiota.openApiExplorer.name": "Kiota OpenAPI Explorer", + "kiota.openApiExplorer.name": "API Explorer", "kiota.openApiExplorer.contextualTitle": "OpenAPI Explorer", "kiota-dependencies-info.panel.title": "Kiota Dependencies Information", - "kiota-openapi-explorer.activitybar.title": "Kiota OpenAPI Explorer", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Select lock file for API explorer view", "kiota.updateClients.title": "Update API clients in the current workspace", - "kiota.openApiExplorer.generateClient.title": "Generate API client", - "kiota.searchApiDescription.title": "Search for an API description", + "kiota.openApiExplorer.generateClient.title": "Generate", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Add", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Remove", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Add all", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Remove all", "kiota.openApiExplorer.closeDescription.title": "Close API description", - "kiota.openApiExplorer.openDescription.title": "Open API description", - "kiota.openApiExplorer.welcome": "No API description selected.\n[Search](command:kiota.searchApiDescription)\n[Open API description](command:kiota.openApiExplorer.openDescription)\n[Open a manifest](command:kiota.openApiExplorer.openManifestPath)\n[Paste a manifest](command:kiota.openApiExplorer.pasteManifest)\n[Select lock file](command:kiota.searchLock)", + "kiota.openApiExplorer.openDescription.title": "Add API description", "kiota.searchLock.title": "Search for a lock file", "kiota.openApiExplorer.filterDescription.title": "Filter API description", "kiota.openApiExplorer.openDocumentationPage.title": "Open documentation page", - "kiota.openApiExplorer.openManifestPath.title": "Open API manifest", - "kiota.openApiExplorer.pasteManifest.title": "Paste API manifest", "kiota.generate.backingStore.description": "Enables backing store for models", "kiota.generate.excludeBackwardCompatible.description": "Excludes backward compatible and obsolete assets from the generated result. Should be used for new clients", "kiota.cleanOutput.description": "Removes all files from the output directory before generating the code files", @@ -29,5 +25,11 @@ "kiota.generate.serializer.description": "The fully qualified class names for serializers", "kiota.generate.deserializer.description": "The fully qualified class names for deserializers", "kiota.generate.structuredMimeTypes.description": "The MIME types and preference to use for structured data model generation. As per RFC9110 Accept header notation.", - "kiota.generate.includeAdditionalData.description": "Will include the 'AdditionalData' property for models" + "kiota.generate.includeAdditionalData.description": "Will include the 'AdditionalData' property for models", + "kiota.openApiExplorer.openFile.title": "Open file", + "kiota.workspace.name": "My Workspace", + "kiota.openApiExplorer.regenerateButton.title": "Re-generate", + "kiota.openApiExplorer.editPaths.title": "Edit paths", + "kiota.openApiExplorer.refresh.title": "Refresh", + "kiota.migrateClients.title": "Migrate API clients" } diff --git a/vscode/microsoft-kiota/package.nls.pl.json b/vscode/microsoft-kiota/package.nls.pl.json index 0cce8f2530..91b4870fb8 100644 --- a/vscode/microsoft-kiota/package.nls.pl.json +++ b/vscode/microsoft-kiota/package.nls.pl.json @@ -4,7 +4,7 @@ "kiota.openApiExplorer.name": "Przeglądarka OpenAPI Kiota", "kiota.openApiExplorer.contextualTitle": "Przeglądarka OpenAPI", "kiota-dependencies-info.panel.title": "Informacje o zależnościach Kiota", - "kiota-openapi-explorer.activitybar.title": "Przeglądarka OpenAPI Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Wybierz plik lock dla widoku eksploratora API", "kiota.updateClients.title": "Zaktualizuj klientów API w bieżącej przestrzeni roboczej", "kiota.openApiExplorer.generateClient.title": "Generuj klienta API", @@ -15,12 +15,9 @@ "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Usuń wszystkie", "kiota.openApiExplorer.closeDescription.title": "Zamknij opis API", "kiota.openApiExplorer.openDescription.title": "Otwórz opis API", - "kiota.openApiExplorer.welcome": "Nie wybrano opisu API.\n[Wyszukaj](command:kiota.searchApiDescription)\n[Otwórz opis API](command:kiota.openApiExplorer.openDescription)\n[Otwórz manifest](command:kiota.openApiExplorer.openManifestPath)\n[Wklej manifest](command:kiota.openApiExplorer.pasteManifest)\n[Wybierz plik lock](command:kiota.searchLock)", "kiota.searchLock.title": "Wyszukaj plik lock", "kiota.openApiExplorer.filterDescription.title": "Filtruj opis API", "kiota.openApiExplorer.openDocumentationPage.title": "Otwórz stronę dokumentacji", - "kiota.openApiExplorer.openManifestPath.title": "Otwórz manifest API", - "kiota.openApiExplorer.pasteManifest.title": "Wklej manifest API", "kiota.generate.backingStore.description": "Włącza kopię zapasową dla modeli", "kiota.generate.excludeBackwardCompatible.description": "Wyklucza zgodne wstecz i przestarzałe zasoby z wyniku generacji. Należy używać w przypadku nowych klientów", "kiota.cleanOutput.description": "Usuwa wszystkie pliki z katalogu wyjściowego przed wygenerowaniem plików kodu", @@ -29,5 +26,10 @@ "kiota.generate.serializer.description": "Pełne nazwy klas dla serializatorów", "kiota.generate.deserializer.description": "Pełne nazwy klas dla deserializatorów", "kiota.generate.structuredMimeTypes.description": "Typy MIME i preferencje do użycia dla generacji modeli danych strukturalnych. Zgodnie z notacją nagłówka Accept RFC9110.", - "kiota.generate.includeAdditionalData.description": "Doda właściwości 'AdditionalData' do modeli" -} \ No newline at end of file + "kiota.generate.includeAdditionalData.description": "Doda właściwości 'AdditionalData' do modeli", + "kiota.workspace.name": "Moja przestrzeń robocza", + "kiota.openApiExplorer.regenerateButton.title": "Ponownie wygeneruj", + "kiota.openApiExplorer.editPaths.title": "Edytuj ścieżki", + "kiota.openApiExplorer.refresh.title": "Odśwież", + "kiota.migrateClients.title": "Migruj klientów API" +} diff --git a/vscode/microsoft-kiota/package.nls.pt.json b/vscode/microsoft-kiota/package.nls.pt.json index 3315187181..76f1b780b8 100644 --- a/vscode/microsoft-kiota/package.nls.pt.json +++ b/vscode/microsoft-kiota/package.nls.pt.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Explorador de OpenAPI do Kiota", "kiota.openApiExplorer.contextualTitle": "Explorador de OpenAPI", "kiota-dependencies-info.panel.title": "Informação de dependências do Kiota", - "kiota-openapi-explorer.activitybar.title": "Explorador de OpenAPI do Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Selecione o arquivo 'lock' para visualizar o explorador de API", "kiota.updateClients.title": "Atualizar os clientes de APIs no espaço de trabalho atual", "kiota.openApiExplorer.generateClient.title": "Gerar cliente da API", - "kiota.searchApiDescription.title": "Procurar por uma descrição de API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Adicionar", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Remover", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Adicionar todos", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Remover todos", "kiota.openApiExplorer.closeDescription.title": "Fechar a descrição da API", "kiota.openApiExplorer.openDescription.title": "Abrir a descrição da API", - "kiota.openApiExplorer.welcome": "Nenhuma descrição de API selecionada.\n[Procurar](command:kiota.searchApiDescription)\n[Abrir a descrição da API](command:kiota.openApiExplorer.openDescription)\n[Abrir um manifesto](command:command:kiota.openApiExplorer.openManifestPath)\n[Colar um manifesto](command:kiota.openApiExplorer.pasteManifest)\n[Selecionar arquivo lock](command:kiota.searchLock)", "kiota.searchLock.title": "Buscar um arquivo lock", "kiota.openApiExplorer.filterDescription.title": "Filtrar descrição da API", "kiota.openApiExplorer.openDocumentationPage.title": "Abrir página de documentação", - "kiota.openApiExplorer.openManifestPath.title": "Abrir manifesto da API", - "kiota.openApiExplorer.pasteManifest.title": "Colar manifesto da API", "kiota.generate.backingStore.description": "Habilita armazenamento de apoio para os modelos", "kiota.generate.excludeBackwardCompatible.description": "Exclui retrocompatibilidade e ativos obsoletos do resultado gerado. Deve ser usado para novos clientes", "kiota.cleanOutput.description": "Remove todos os arquivos do diretório de saída antes de gerar os arquivos de código", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "O nome totalmente qualificado da classe para serializadores", "kiota.generate.deserializer.description": "O nome totalmente qualificado da classe para desserializadores", "kiota.generate.structuredMimeTypes.description": "As preferências e os tipos MIME a serem usados para a geração de modelos de dados estruturados. De acordo com a notação do cabeçalho Accept do RFC9110..", - "kiota.generate.includeAdditionalData.description": "Será incluído a propriedade 'AdditionalData' para modelos" + "kiota.generate.includeAdditionalData.description": "Será incluído a propriedade 'AdditionalData' para modelos", + "kiota.workspace.name": "Meu espaço de trabalho", + "kiota.openApiExplorer.regenerateButton.title": "Gerar novamente", + "kiota.openApiExplorer.editPaths.title": "Modificar endpoints", + "kiota.openApiExplorer.refresh.title": "Atualizar", + "kiota.migrateClients.title": "Migrar clientes de API" } diff --git a/vscode/microsoft-kiota/package.nls.ru.json b/vscode/microsoft-kiota/package.nls.ru.json index b5f5d795dd..5e4db32ccc 100644 --- a/vscode/microsoft-kiota/package.nls.ru.json +++ b/vscode/microsoft-kiota/package.nls.ru.json @@ -4,21 +4,31 @@ "kiota.openApiExplorer.name": "OpenAPI исследователь для Kiota", "kiota.openApiExplorer.contextualTitle": "OpenAPI исследователь", "kiota-dependencies-info.panel.title": "Информация о зависимостях Kiota", - "kiota-openapi-explorer.activitybar.title": "OpenAPI исследователь для Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Выберите файл блокировки для просмотра API-исследователя", "kiota.updateClients.title": "Обновите API-клиенты в текущем рабочем пространстве", "kiota.openApiExplorer.generateClient.title": "Создать клиент API", - "kiota.searchApiDescription.title": "Искать описание API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Добавить", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Удалить", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Добавить всё", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Удалить всё", "kiota.openApiExplorer.closeDescription.title": "Закрыть описание API", "kiota.openApiExplorer.openDescription.title": "Открыть описание API", - "kiota.openApiExplorer.welcome": "Не выбрано описание API.\n[поиск](command:kiota.searchApiDescription)\n[Открыть описание API](command:kiota.openApiExplorer.openDescription)\n[Вставьте манифест](command:kiota.openApiExplorer.openManifestPath)\n[Откройте манифест](command:kiota.openApiExplorer.pasteManifest)\n[выделить](command:kiota.searchLock)", "kiota.searchLock.title": "Искать файл блокировки", "kiota.openApiExplorer.filterDescription.title": "Отфильтровать описание API", "kiota.openApiExplorer.openDocumentationPage.title": "Открыть страницу документации", - "kiota.openApiExplorer.openManifestPath.title": "Откройте манифест API", - "kiota.openApiExplorer.pasteManifest.title": "Вставьте манифест API" + "kiota.generate.backingStore.description": "Включить резервное хранилище для моделей", + "kiota.generate.excludeBackwardCompatible.description": "Исключить совместимые с предыдущими версиями и устаревшие активы из сгенерированного результата. Следует использовать для новых клиентов", + "kiota.cleanOutput.description": "Удалить все файлы из каталога вывода перед созданием файлов кода", + "kiota.generate.disabledValidationRules.description": "Правила проверки описания OpenAPI для отключения: \nDivergentResponseSchema\nGetWithBody\nInconsistentTypeFormatPair\nKnownAndNotSupportedFormats\nMissingDiscriminator\nMultipleServerEntries\nNoContentWithBody\nNoServerEntry\nUrlFormEncodedComplex\nValidationRuleSetExtensions\nAll", + "kiota.clearCache.description": "Очистить любые кэшированные данные", + "kiota.generate.serializer.description": "Полностью квалифицированные имена классов для сериализаторов", + "kiota.generate.deserializer.description": "Полностью квалифицированные имена классов для десериализаторов", + "kiota.generate.structuredMimeTypes.description": "Типы MIME и предпочтения для использования при создании структурированных моделей данных. Согласно нотации заголовка Accept RFC9110.", + "kiota.generate.includeAdditionalData.description": "Будет включено свойство 'Дополнительные данные' для моделей", + "kiota.workspace.name": "Мое рабочее пространство", + "kiota.openApiExplorer.regenerateButton.title": "Пересоздать", + "kiota.openApiExplorer.editPaths.title": "Изменить пути", + "kiota.openApiExplorer.refresh.title": "Обновить", + "kiota.migrateClients.title": "Перенести API-клиенты" } diff --git a/vscode/microsoft-kiota/package.nls.sw.json b/vscode/microsoft-kiota/package.nls.sw.json index 1f11640bf3..b4946bacb8 100644 --- a/vscode/microsoft-kiota/package.nls.sw.json +++ b/vscode/microsoft-kiota/package.nls.sw.json @@ -4,21 +4,23 @@ "kiota.openApiExplorer.name": "Mchunguzi wa OpenAPI Kiota", "kiota.openApiExplorer.contextualTitle": "Mchunguzi wa OpenAPI", "kiota-dependencies-info.panel.title": "Taarifa za Mategemeo za Kiota", - "kiota-openapi-explorer.activitybar.title": "Mchunguzi wa OpenAPI Kiota", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "Chagua faili ya kufunga ili uone kichunguzi cha API", "kiota.updateClients.title": "Sasisha wateja wa API katika nafasi ya kazi", "kiota.openApiExplorer.generateClient.title": "Tengeneza mteja wa API", - "kiota.searchApiDescription.title": "Tafuta maelezo ya API", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Ongeza", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Ondoa", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Ongeza yote", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Ondoa yote", "kiota.openApiExplorer.closeDescription.title": "Funga maelezo ya API", "kiota.openApiExplorer.openDescription.title": "Fungua maelezo ya API", - "kiota.openApiExplorer.welcome": "Hakuna maelezo ya API yaliyochaguliwa.\n[Tafuta](command:kiota.searchApiDescription)\n[Fungua maelezo ya API](command:kiota.openApiExplorer.openDescription)\n[Fungua faili ya dhahiri](command:kiota.openApiExplorer.openManifestPath)\\n[Bandika faili ya dhahiri](command:kiota.openApiExplorer.pasteManifest)\n[Chagua faili ya kufunga](command:kiota.searchLock)", "kiota.searchLock.title": "Tafuta faili ya kufunga", "kiota.openApiExplorer.filterDescription.title": "Chuja maelezo ya API", "kiota.openApiExplorer.openDocumentationPage.title": "Fungua ukurasa wa nyaraka", - "kiota.openApiExplorer.openManifestPath.title": "Fungua dhahiri ya API", - "kiota.openApiExplorer.pasteManifest.title": "Bandiko dhahiri ya dhahiri" + "kiota.openApiExplorer.openFile.title": "fungua faili", + "kiota.workspace.name": "Mahali pa kazi yangu", + "kiota.openApiExplorer.regenerateButton.title": "Kuunda upya", + "kiota.openApiExplorer.editPaths.title": "Hariri pointi za mwisho", + "kiota.openApiExplorer.refresh.title": "Sasisha", + "kiota.migrateClients.title": "Hamisha wateja wa API" } diff --git a/vscode/microsoft-kiota/package.nls.tr.json b/vscode/microsoft-kiota/package.nls.tr.json index 7bd652f264..2956d11157 100644 --- a/vscode/microsoft-kiota/package.nls.tr.json +++ b/vscode/microsoft-kiota/package.nls.tr.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Kiota OpenAPI Gezgini", "kiota.openApiExplorer.contextualTitle": "OpenAPI Gezgini", "kiota-dependencies-info.panel.title": "Kiota Bağımlılıkları Bilgisi", - "kiota-openapi-explorer.activitybar.title": "Kiota OpenAPI Gezgini", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "API gezgini görünümü için kilit dosyasını seçin", "kiota.updateClients.title": "Mevcut çalışma alanındaki API istecilerini güncelle", "kiota.openApiExplorer.generateClient.title": "API istemcisi oluştur", - "kiota.searchApiDescription.title": "API açıklaması ara", "kiota.openApiExplorer.addToSelectedEndpoints.title": "Ekle", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "Kaldır", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "Tümünü ekle", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "Tümünü kaldır", "kiota.openApiExplorer.closeDescription.title": "API açıklamasını kapat", "kiota.openApiExplorer.openDescription.title": "API açıklamasını aç", - "kiota.openApiExplorer.welcome": "Seçili bir API açıklaması yok.\n[Ara](command:kiota.searchApiDescription)\n[Aç](command:kiota.openApiExplorer.openDescription)\n[Kilit dosyasını seç](command:kiota.searchLock)", "kiota.searchLock.title": "Kilit dosyası arayın", "kiota.openApiExplorer.filterDescription.title": "API açıklaması filtrele", "kiota.openApiExplorer.openDocumentationPage.title": "API belgelerini aç", - "kiota.openApiExplorer.openManifestPath.title": "API manifestini aç", - "kiota.openApiExplorer.pasteManifest.title": "API manifestini yapıştır", "kiota.generate.backingStore.description": "Modeller için yedekleme deposunu etkinleştirir", "kiota.generate.excludeBackwardCompatible.description": "Geriye dönük olarak uyumlu ve eski varlıkları oluşturulan sonuçtan hariç tutar. Yeni müşteriler için kullanılmalı", "kiota.cleanOutput.description": "Kod dosyalarını oluşturmadan önce çıktı dizinindeki tüm dosyaları kaldırır", @@ -29,5 +25,10 @@ "kiota.generate.serializer.description": "Serileştiriciler için tam nitelikli sınıf adları", "kiota.generate.deserializer.description": "Seri durumdan çıkarma işlemleri için tam nitelikli sınıf adları", "kiota.generate.structuredMimeTypes.description": "Yapılandırılmış veri modeli oluşturmak için kullanılacak MIME türleri ve tercihi. RFC9110'a göre Başlık gösterimini kabul et.", - "kiota.generate.includeAdditionalData.description": "Modeller için 'AdditionalData' özelliğini içerecektir" + "kiota.generate.includeAdditionalData.description": "Modeller için 'AdditionalData' özelliğini içerecektir", + "kiota.workspace.name": "Çalışma Alanım", + "kiota.openApiExplorer.regenerateButton.title": "Yeniden oluştur", + "kiota.openApiExplorer.editPaths.title": "Yolları düzenle", + "kiota.openApiExplorer.refresh.title": "Yenile", + "kiota.migrateClients.title": "API istemcilerini taşı" } diff --git a/vscode/microsoft-kiota/package.nls.zh-cn.json b/vscode/microsoft-kiota/package.nls.zh-cn.json index f24ca8c9aa..7aaa9d1dce 100644 --- a/vscode/microsoft-kiota/package.nls.zh-cn.json +++ b/vscode/microsoft-kiota/package.nls.zh-cn.json @@ -4,23 +4,19 @@ "kiota.openApiExplorer.name": "Kiota OpenAPI 资源浏览器", "kiota.openApiExplorer.contextualTitle": "OpenAPI 资源浏览器", "kiota-dependencies-info.panel.title": "Kiota依赖项信息", - "kiota-openapi-explorer.activitybar.title": "Kiota OpenAPI 资源浏览器", + "kiota-openapi-explorer.activitybar.title": "Kiota", "kiota.selectLock.title": "选择API资源浏览器的锁定文件", "kiota.updateClients.title": "更新当前工作区API客户端", "kiota.openApiExplorer.generateClient.title": "建立API客户端", - "kiota.searchApiDescription.title": "搜索API描述", "kiota.openApiExplorer.addToSelectedEndpoints.title": "添加", "kiota.openApiExplorer.removeFromSelectedEndpoints.title": "删除", "kiota.openApiExplorer.addAllToSelectedEndpoints.title": "添加所有", "kiota.openApiExplorer.removeAllFromSelectedEndpoints.title": "删除所有", "kiota.openApiExplorer.closeDescription.title": "关闭API描述文档", "kiota.openApiExplorer.openDescription.title": "打开API描述文档", - "kiota.openApiExplorer.welcome": "无API描述文档选择.\n[搜索](command:kiota.searchApiDescription)\n[打开API描述文档](command:kiota.openApiExplorer.openDescription)\n[打开清单](command:command:kiota.openApiExplorer.openManifestPath)\n[粘贴清单](command:kiota.openApiExplorer.pasteManifest)\n[选择锁定文件](command:kiota.searchLock)", "kiota.searchLock.title": "搜索锁定文件", "kiota.openApiExplorer.filterDescription.title": "筛选API描述", "kiota.openApiExplorer.openDocumentationPage.title": "打开文档页", - "kiota.openApiExplorer.openManifestPath.title": "打开API清单", - "kiota.openApiExplorer.pasteManifest.title": "粘贴API清单", "kiota.generate.backingStore.description": "启用模型后备存储", "kiota.generate.excludeBackwardCompatible.description": "从生成的结果中排除向后兼容和过时的资产。应该用于新客户端", "kiota.cleanOutput.description": "在生成代码文件之前从输出目录中删除所有文件", @@ -29,5 +25,8 @@ "kiota.generate.serializer.description": "合格的序列化器类名", "kiota.generate.deserializer.description": "合格的反序列化器类名", "kiota.generate.structuredMimeTypes.description": "用于生成结构化数据模型的 MIME 类型和首选项。根据符合 RFC9110 标题符号。", - "kiota.generate.includeAdditionalData.description": "将包含模型的“AdditionalData”属性" + "kiota.generate.includeAdditionalData.description": "将包含模型的“AdditionalData”属性", + "kiota.workspace.name": "我的工作空间", + "kiota.openApiExplorer.regenerateButton.title": "重新生成", + "kiota.openApiExplorer.editPaths.title": "编辑路径" } diff --git a/vscode/microsoft-kiota/src/codelensProvider.ts b/vscode/microsoft-kiota/src/codelensProvider.ts new file mode 100644 index 0000000000..274fc46805 --- /dev/null +++ b/vscode/microsoft-kiota/src/codelensProvider.ts @@ -0,0 +1,48 @@ +import * as vscode from 'vscode'; +import { l10n } from 'vscode'; +import { CLIENTS, KIOTA_WORKSPACE_FILE, PLUGINS } from './constants'; + +export class CodeLensProvider implements vscode.CodeLensProvider { + public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult { + const codeLenses: vscode.CodeLens[] = []; + const text = document.getText(); + const jsonObject = JSON.parse(text); + + if (document.fileName.endsWith(KIOTA_WORKSPACE_FILE)) { + [CLIENTS, PLUGINS].forEach(objectKey => { + const object = jsonObject[objectKey]; + if (object) { + Object.keys(object).forEach(key => { + const obj = object[key]; + const startLine = this.findPropertyLine(text, key); + if (startLine !== -1) { + const positionBeforeObj = new vscode.Position(startLine, 0); + const rangeBeforeObj = new vscode.Range(positionBeforeObj, positionBeforeObj); + + const editPathsCommand = { + title: l10n.t("Edit Paths"), + command: "kiota.editPaths", + arguments: [key, obj, objectKey] + }; + codeLenses.push(new vscode.CodeLens(rangeBeforeObj, editPathsCommand)); + + const regenerateCommand = { + title: l10n.t("Re-generate"), + command: "kiota.regenerate", + arguments: [key, obj, objectKey] + }; + codeLenses.push(new vscode.CodeLens(rangeBeforeObj, regenerateCommand)); + } + }); + } + }); + } + return codeLenses; + } + + private findPropertyLine(text: string, property: string): number { + const propertyRegex = new RegExp(`"${property}"\\s*:\\s*{`); + const match = text.match(propertyRegex); + return match ? text.substr(0, match.index).split('\n').length - 1 : -1; + } +} \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/constants.ts b/vscode/microsoft-kiota/src/constants.ts new file mode 100644 index 0000000000..45c775da13 --- /dev/null +++ b/vscode/microsoft-kiota/src/constants.ts @@ -0,0 +1,16 @@ +export const extensionId = "kiota"; +export const focusCommandId = ".focus"; +export const statusBarCommandId = `${extensionId}.status`; +export const treeViewId = `${extensionId}.openApiExplorer`; +export const treeViewFocusCommand = `${treeViewId}${focusCommandId}`; +export const dependenciesInfo = `${extensionId}.dependenciesInfo`; +export const KIOTA_LOCK_FILE = "kiota-lock.json"; +export const KIOTA_WORKSPACE_FILE = "workspace.json"; +export const KIOTA_DIRECTORY = '.kiota'; +export const CLIENTS = "clients"; +export const PLUGINS = "plugins"; +export const CLIENT = "client"; +export const PLUGIN = "plugin"; +export const APIMANIFEST = "apimanifest"; +export const REMIND_ME_LATER_FLAG = 'remindMeLater'; + diff --git a/vscode/microsoft-kiota/src/extension.ts b/vscode/microsoft-kiota/src/extension.ts index db60f3cb88..378455ae86 100644 --- a/vscode/microsoft-kiota/src/extension.ts +++ b/vscode/microsoft-kiota/src/extension.ts @@ -6,32 +6,43 @@ import * as path from 'path'; import * as fs from 'fs'; import { OpenApiTreeNode, OpenApiTreeProvider } from "./openApiTreeProvider"; import { + ClientOrPluginProperties, + ConsumerOperation, generationLanguageToString, getLogEntriesForLevel, KiotaGenerationLanguage, KiotaLogEntry, + KiotaPluginType, LogLevel, parseGenerationLanguage, + parsePluginType, } from "./kiotaInterop"; -import { filterSteps, generateSteps, openManifestSteps, openSteps, searchLockSteps, searchSteps, selectApiManifestKey } from "./steps"; +import { GenerateState, GenerationType, filterSteps, generateSteps, parseGenerationType, searchSteps } from "./steps"; import { getKiotaVersion } from "./getKiotaVersion"; import { searchDescription } from "./searchDescription"; import { generateClient } from "./generateClient"; import { getLanguageInformation, getLanguageInformationForDescription } from "./getLanguageInformation"; import { DependenciesViewProvider } from "./dependenciesViewProvider"; import { updateClients } from "./updateClients"; -import { ApiManifest } from "./apiManifest"; -import { getExtensionSettings } from "./extensionSettings"; +import { ExtensionSettings, getExtensionSettings } from "./extensionSettings"; +import { loadTreeView } from "./workspaceTreeProvider"; +import { generatePlugin } from "./generatePlugin"; +import { CodeLensProvider } from "./codelensProvider"; +import { KIOTA_WORKSPACE_FILE, dependenciesInfo, extensionId, statusBarCommandId, treeViewFocusCommand, treeViewId } from "./constants"; +import { getWorkspaceJsonDirectory, getWorkspaceJsonPath, handleMigration, isClientType, isPluginType, updateTreeViewIcons } from "./util"; +import { checkForLockFileAndPrompt } from "./migrateFromLockFile"; let kiotaStatusBarItem: vscode.StatusBarItem; let kiotaOutputChannel: vscode.LogOutputChannel; -const extensionId = "kiota"; -const focusCommandId = ".focus"; -const statusBarCommandId = `${extensionId}.status`; -const treeViewId = `${extensionId}.openApiExplorer`; -const treeViewFocusCommand = `${treeViewId}${focusCommandId}`; -const dependenciesInfo = `${extensionId}.dependenciesInfo`; -export const kiotaLockFile = "kiota-lock.json"; +let clientOrPluginKey: string; +let clientOrPluginObject: ClientOrPluginProperties; +let workspaceGenerationType: string; +let config: Partial; + +interface GeneratedOutputState { + outputPath: string; + clientClassName: string; +} // This method is called when your extension is activated // Your extension is activated the very first time the command is executed @@ -46,6 +57,9 @@ export async function activate( context.extensionUri ); const reporter = new TelemetryReporter(context.extension.packageJSON.telemetryInstrumentationKey); + await loadTreeView(context); + await checkForLockFileAndPrompt(context); + let codeLensProvider = new CodeLensProvider(); context.subscriptions.push( vscode.window.registerUriHandler({ handleUri: async (uri: vscode.Uri) => { @@ -61,46 +75,17 @@ export async function activate( return; } } - if (uri.path.toLowerCase() === "/openmanifest") { - reporter.sendTelemetryEvent("DeepLink.OpenManifest"); - const manifestUrl = queryParameters["manifesturl"]; - const manifestContent = queryParameters["manifestcontent"]; - const apiIdentifier = queryParameters["apiidentifier"]; - const fromClipboard = queryParameters["fromclipboard"]; - if (manifestUrl) { - await openTreeViewWithProgress(async () => { - const logs = await openApiTreeProvider.loadManifestFromUri(manifestUrl, apiIdentifier); - await exportLogsAndShowErrors(logs); - }); - return; - } else if (manifestContent) { - await openTreeViewWithProgress(async () => { - const logs = await openApiTreeProvider.loadManifestFromContent(manifestContent, apiIdentifier); - await exportLogsAndShowErrors(logs); - }); - return; - } else if (fromClipboard.toLowerCase() === "true") { - await openManifestFromClipboard(openApiTreeProvider, apiIdentifier!); - return; - } - } void vscode.window.showErrorMessage( vscode.l10n.t("Invalid URL, please check the documentation for the supported URLs") ); } }), + + vscode.languages.registerCodeLensProvider('json', codeLensProvider), reporter, - registerCommandWithTelemetry(reporter, - `${extensionId}.searchLock`, - async () => { - const lockFilePath = await searchLockSteps(); - if (lockFilePath?.lockFilePath) { - await loadLockFile(lockFilePath.lockFilePath, openApiTreeProvider); - } - }), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${extensionId}.selectLock`, - (x) => loadLockFile(x, openApiTreeProvider) + (x) => loadWorkspaceFile(x, openApiTreeProvider) ), registerCommandWithTelemetry(reporter, statusBarCommandId, async () => { const yesAnswer = vscode.l10n.t("Yes"); @@ -118,27 +103,27 @@ export async function activate( dependenciesInfoProvider ), vscode.window.registerTreeDataProvider(treeViewId, openApiTreeProvider), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.openDocumentationPage`, (x: OpenApiTreeNode) => x.documentationUrl && vscode.env.openExternal(vscode.Uri.parse(x.documentationUrl)) ), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.addToSelectedEndpoints`, (x: OpenApiTreeNode) => openApiTreeProvider.select(x, true, false) ), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.addAllToSelectedEndpoints`, (x: OpenApiTreeNode) => openApiTreeProvider.select(x, true, true) ), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.removeFromSelectedEndpoints`, (x: OpenApiTreeNode) => openApiTreeProvider.select(x, false, false) ), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.removeAllFromSelectedEndpoints`, (x: OpenApiTreeNode) => openApiTreeProvider.select(x, false, true) ), - registerCommandWithTelemetry(reporter, + registerCommandWithTelemetry(reporter, `${treeViewId}.generateClient`, async () => { const selectedPaths = openApiTreeProvider.getSelectedPaths(); @@ -148,17 +133,9 @@ export async function activate( ); return; } - if ( - !vscode.workspace.workspaceFolders || - vscode.workspace.workspaceFolders.length === 0 - ) { - await vscode.window.showErrorMessage( - vscode.l10n.t("No workspace folder found, open a folder first") - ); - return; - } + let languagesInformation = await getLanguageInformation(context); - const config = await generateSteps( + config = await generateSteps( { clientClassName: openApiTreeProvider.clientClassName, clientNamespaceName: openApiTreeProvider.clientNamespaceName, @@ -167,9 +144,10 @@ export async function activate( }, languagesInformation ); + const generationType = parseGenerationType(config.generationType); const outputPath = typeof config.outputPath === "string" - ? config.outputPath - : "./output"; + ? config.outputPath + : "./output"; await showUpgradeWarningMessage(outputPath, context); if (!openApiTreeProvider.descriptionUrl) { await vscode.window.showErrorMessage( @@ -177,74 +155,65 @@ export async function activate( ); return; } - const language = - typeof config.language === "string" - ? parseGenerationLanguage(config.language) - : KiotaGenerationLanguage.CSharp; + const settings = getExtensionSettings(extensionId); - const result = await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - cancellable: false, - title: vscode.l10n.t("Generating client...") - }, async (progress, _) => { - const start = performance.now(); - const result = await generateClient( - context, - openApiTreeProvider.descriptionUrl, - outputPath, - language, - selectedPaths, - [], - typeof config.clientClassName === "string" - ? config.clientClassName - : "ApiClient", - typeof config.clientNamespaceName === "string" - ? config.clientNamespaceName - : "ApiSdk", - settings.backingStore, - settings.clearCache, - settings.cleanOutput, - settings.excludeBackwardCompatible, - settings.disableValidationRules, - settings.languagesSerializationConfiguration[language].serializers, - settings.languagesSerializationConfiguration[language].deserializers, - settings.structuredMimeTypes, - settings.includeAdditionalData - ); - const duration = performance.now() - start; - const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; - reporter.sendRawTelemetryEvent(`${extensionId}.generateClient.completed`, { - "language": generationLanguageToString(language), - "errorsCount": errorsCount.toString(), - }, { - "duration": duration, - }); - return result; - }); - - languagesInformation = await getLanguageInformationForDescription( - context, - openApiTreeProvider.descriptionUrl, - settings.clearCache - ); - if (languagesInformation) { - dependenciesInfoProvider.update(languagesInformation, language); - await vscode.commands.executeCommand(treeViewFocusCommand); - } - if (typeof config.outputPath === "string" && !openApiTreeProvider.isLockFileLoaded && - vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0 && - result && getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length === 0) { - await openApiTreeProvider.loadLockFile(path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, config.outputPath, kiotaLockFile)); + workspaceGenerationType = config.generationType as string; + let result; + switch (generationType) { + case GenerationType.Client: + result = await generateClientAndRefreshUI(config, settings, outputPath, selectedPaths); + break; + case GenerationType.Plugin: + result = await generatePluginAndRefreshUI(config, settings, outputPath, selectedPaths); + break; + case GenerationType.ApiManifest: + result = await generateManifestAndRefreshUI(config, settings, outputPath, selectedPaths); + break; + default: + await vscode.window.showErrorMessage( + vscode.l10n.t("Invalid generation type") + ); + return; } - if (result) - { - await exportLogsAndShowErrors(result); + if (result && getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length === 0) { + // Save state before opening the new window + void context.workspaceState.update('generatedOutput', { + outputPath, + config, + clientClassName: config.clientClassName || config.pluginName + } as GeneratedOutputState); + if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) { + await vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(config.workingDirectory ?? getWorkspaceJsonDirectory()), true); + } else { + await displayGenerationResults(context, openApiTreeProvider, config); + } } } ), - registerCommandWithTelemetry(reporter, - `${extensionId}.searchApiDescription`, + vscode.workspace.onDidChangeWorkspaceFolders(async () => { + const generatedOutput = context.workspaceState.get('generatedOutput'); + if (generatedOutput) { + const { outputPath } = generatedOutput; + await displayGenerationResults(context, openApiTreeProvider, config); + // Clear the state + void context.workspaceState.update('generatedOutput', undefined); + } + }), + registerCommandWithTelemetry(reporter, + `${treeViewId}.searchOrOpenApiDescription`, async () => { + const yesAnswer = vscode.l10n.t("Yes, override it"); + if (!openApiTreeProvider.isEmpty() && openApiTreeProvider.hasChanges()) { + const response = await vscode.window.showWarningMessage( + vscode.l10n.t( + "Before adding a new API description, consider that your changes and current selection will be lost."), + yesAnswer, + vscode.l10n.t("Cancel") + ); + if (response !== yesAnswer) { + return; + } + } const config = await searchSteps(x => vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: false, @@ -258,37 +227,329 @@ export async function activate( } } ), - registerCommandWithTelemetry(reporter, `${treeViewId}.closeDescription`, () => - openApiTreeProvider.closeDescription() + registerCommandWithTelemetry(reporter, `${treeViewId}.closeDescription`, async () => { + const yesAnswer = vscode.l10n.t("Yes"); + const response = await vscode.window.showInformationMessage( + vscode.l10n.t("Do you want to remove this API description?"), + yesAnswer, + vscode.l10n.t("No") + ); + if (response === yesAnswer) { + openApiTreeProvider.closeDescription(); + await updateTreeViewIcons(treeViewId, false); + } + } ), registerCommandWithTelemetry(reporter, `${treeViewId}.filterDescription`, async () => { await filterSteps(openApiTreeProvider.filter, x => openApiTreeProvider.filter = x); } ), - registerCommandWithTelemetry(reporter, - `${treeViewId}.openDescription`, - async () => { - const openState = await openSteps(); - if (openState.descriptionPath) { - await openTreeViewWithProgress(() => openApiTreeProvider.setDescriptionUrl(openState.descriptionPath!)); + registerCommandWithTelemetry(reporter, `${extensionId}.editPaths`, async (clientKey: string, clientObject: ClientOrPluginProperties, generationType: string) => { + clientOrPluginKey = clientKey; + clientOrPluginObject = clientObject; + workspaceGenerationType = generationType; + await loadEditPaths(clientOrPluginKey, clientObject, openApiTreeProvider); + openApiTreeProvider.resetInitialState(); + await updateTreeViewIcons(treeViewId, false, true); + }), + registerCommandWithTelemetry(reporter, `${treeViewId}.regenerateButton`, async () => { + if (!clientOrPluginKey || clientOrPluginKey === '') { + clientOrPluginKey = config.clientClassName || config.pluginName || ''; + } + if (!config) { + config = { + outputPath: clientOrPluginObject.outputPath, + clientClassName: clientOrPluginKey, + }; + } + const settings = getExtensionSettings(extensionId); + const selectedPaths = openApiTreeProvider.getSelectedPaths(); + if (selectedPaths.length === 0) { + await vscode.window.showErrorMessage( + vscode.l10n.t("No endpoints selected, select endpoints first") + ); + return; + } + if (isClientType(workspaceGenerationType)) { + await regenerateClient(clientOrPluginKey, config, settings, selectedPaths); + } + if (isPluginType(workspaceGenerationType)) { + await regeneratePlugin(clientOrPluginKey, config, settings, selectedPaths); + } + }), + registerCommandWithTelemetry(reporter, `${extensionId}.regenerate`, async (clientKey: string, clientObject: ClientOrPluginProperties, generationType: string) => { + const settings = getExtensionSettings(extensionId); + const workspaceJson = vscode.workspace.textDocuments.find(doc => doc.fileName.endsWith(KIOTA_WORKSPACE_FILE)); + if (workspaceJson && workspaceJson.isDirty) { + await vscode.window.showInformationMessage( + vscode.l10n.t("Please save the workspace.json file before re-generation."), + vscode.l10n.t("OK") + ); + return; + } + if (isClientType(generationType)) { + await regenerateClient(clientKey, clientObject, settings); + } + if (isPluginType(generationType)) { + await regeneratePlugin(clientKey, clientObject, settings); + } + }), + registerCommandWithTelemetry(reporter, `${extensionId}.migrateFromLockFile`, async (uri: vscode.Uri) => { + const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); + + if (!workspaceFolder) { + vscode.window.showErrorMessage(vscode.l10n.t("Could not determine the workspace folder.")); + return; + } + + await handleMigration(context, workspaceFolder); + }) + ); + + async function generateManifestAndRefreshUI(config: Partial, settings: ExtensionSettings, outputPath: string, selectedPaths: string[]): Promise { + const pluginTypes = KiotaPluginType.ApiManifest; + const result = await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t("Generating manifest...") + }, async (progress, _) => { + const start = performance.now(); + const result = await generatePlugin( + context, + openApiTreeProvider.descriptionUrl, + outputPath, + [pluginTypes], + selectedPaths, + [], + typeof config.pluginName === "string" + ? config.pluginName + : "ApiClient", + settings.clearCache, + settings.cleanOutput, + settings.disableValidationRules, + ConsumerOperation.Add, + config.workingDirectory + ); + const duration = performance.now() - start; + const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; + reporter.sendRawTelemetryEvent(`${extensionId}.generateManifest.completed`, { + "pluginType": pluginTypes.toString(), + "errorsCount": errorsCount.toString(), + }, { + "duration": duration, + }); + return result; + }); + if (result) { + const isSuccess = await checkForSuccess(result); + if (!isSuccess) { + await exportLogsAndShowErrors(result); + } + void vscode.window.showInformationMessage(vscode.l10n.t('Generation completed successfully.')); + } + return result; + } + async function generatePluginAndRefreshUI(config: Partial, settings: ExtensionSettings, outputPath: string, selectedPaths: string[]): Promise { + const pluginTypes = Array.isArray(config.pluginTypes) ? parsePluginType(config.pluginTypes) : [KiotaPluginType.ApiPlugin]; + const result = await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t("Generating plugin...") + }, async (progress, _) => { + const start = performance.now(); + const result = await generatePlugin( + context, + openApiTreeProvider.descriptionUrl, + outputPath, + pluginTypes, + selectedPaths, + [], + typeof config.pluginName === "string" + ? config.pluginName + : "ApiClient", + settings.clearCache, + settings.cleanOutput, + settings.disableValidationRules, + ConsumerOperation.Add, + config.workingDirectory + ); + const duration = performance.now() - start; + const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; + reporter.sendRawTelemetryEvent(`${extensionId}.generatePlugin.completed`, { + "pluginType": pluginTypes.toString(), + "errorsCount": errorsCount.toString(), + }, { + "duration": duration, + }); + return result; + }); + if (result) { + const isSuccess = await checkForSuccess(result); + if (!isSuccess) { + await exportLogsAndShowErrors(result); + } + void vscode.window.showInformationMessage(vscode.l10n.t('Generation completed successfully.')); + } + return result; + } + async function generateClientAndRefreshUI(config: Partial, settings: ExtensionSettings, outputPath: string, selectedPaths: string[]): Promise { + const language = + typeof config.language === "string" + ? parseGenerationLanguage(config.language) + : KiotaGenerationLanguage.CSharp; + const result = await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t("Generating client...") + }, async (progress, _) => { + const start = performance.now(); + const result = await generateClient( + context, + openApiTreeProvider.descriptionUrl, + outputPath, + language, + selectedPaths, + [], + typeof config.clientClassName === "string" + ? config.clientClassName + : "ApiClient", + typeof config.clientNamespaceName === "string" + ? config.clientNamespaceName + : "ApiSdk", + settings.backingStore, + settings.clearCache, + settings.cleanOutput, + settings.excludeBackwardCompatible, + settings.disableValidationRules, + settings.languagesSerializationConfiguration[language].serializers, + settings.languagesSerializationConfiguration[language].deserializers, + settings.structuredMimeTypes, + settings.includeAdditionalData, + ConsumerOperation.Add, + config.workingDirectory + ); + const duration = performance.now() - start; + const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; + reporter.sendRawTelemetryEvent(`${extensionId}.generateClient.completed`, { + "language": generationLanguageToString(language), + "errorsCount": errorsCount.toString(), + }, { + "duration": duration, + }); + return result; + }); + + let languagesInformation = await getLanguageInformationForDescription( + context, + openApiTreeProvider.descriptionUrl, + settings.clearCache + ); + if (languagesInformation) { + dependenciesInfoProvider.update(languagesInformation, language); + await vscode.commands.executeCommand(treeViewFocusCommand); + } + if (result) { + const isSuccess = await checkForSuccess(result); + if (!isSuccess) { + await exportLogsAndShowErrors(result); + } + void vscode.window.showInformationMessage(vscode.l10n.t('Generation completed successfully.')); + } + return result; + } + + async function displayGenerationResults(context: vscode.ExtensionContext, openApiTreeProvider: OpenApiTreeProvider, config: any) { + const clientNameOrPluginName = config.clientClassName || config.pluginName; + openApiTreeProvider.refreshView(); + const workspaceJsonPath = getWorkspaceJsonPath(); + await loadWorkspaceFile({ fsPath: workspaceJsonPath }, openApiTreeProvider, clientNameOrPluginName); + await vscode.commands.executeCommand('kiota.workspace.refresh'); + openApiTreeProvider.resetInitialState(); + await updateTreeViewIcons(treeViewId, false, true); + } + async function regenerateClient(clientKey: string, clientObject: any, settings: ExtensionSettings, selectedPaths?: string[]): Promise { + const language = + typeof clientObject.language === "string" + ? parseGenerationLanguage(clientObject.language) + : KiotaGenerationLanguage.CSharp; + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t("Re-generating client...") + }, async (progress, _) => { + const result = await generateClient( + context, + clientObject.descriptionLocation ? clientObject.descriptionLocation : openApiTreeProvider.descriptionUrl, + clientObject.outputPath, + language, + selectedPaths ? selectedPaths : clientObject.includePatterns, + clientObject.excludePatterns ? clientObject.excludePatterns : [], + clientKey, + clientObject.clientNamespaceName, + clientObject.usesBackingStore ? clientObject.usesBackingStore : settings.backingStore, + true, // clearCache + true, // cleanOutput + clientObject.excludeBackwardCompatible ? clientObject.excludeBackwardCompatible : settings.excludeBackwardCompatible, + clientObject.disabledValidationRules ? clientObject.disabledValidationRules : settings.disableValidationRules, + settings.languagesSerializationConfiguration[language].serializers, + settings.languagesSerializationConfiguration[language].deserializers, + clientObject.structuredMimeTypes ? clientObject.structuredMimeTypes : settings.structuredMimeTypes, + clientObject.includeAdditionalData ? clientObject.includeAdditionalData : settings.includeAdditionalData, + ConsumerOperation.Edit + ); + if (result) { + const isSuccess = await checkForSuccess(result); + if (!isSuccess) { + await exportLogsAndShowErrors(result); } + void vscode.window.showInformationMessage(`Client ${clientKey} re-generated successfully.`); } - ), - registerCommandWithTelemetry(reporter, - `${treeViewId}.openManifestPath`, - async () => { - const openState = await openManifestSteps(); - if (openState.manifestPath) { - await openTreeViewWithProgress(() => openApiTreeProvider.loadManifestFromUri(openState.manifestPath!)); + return result; + }); + + openApiTreeProvider.resetInitialState(); + } + async function regeneratePlugin(clientKey: string, clientObject: any, settings: ExtensionSettings, selectedPaths?: string[]) { + const pluginTypes = Array.isArray(clientObject.types) ? parsePluginType(clientObject.types) : [KiotaPluginType.ApiPlugin]; + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t("Re-generating plugin...") + }, async (progress, _) => { + const start = performance.now(); + const result = await generatePlugin( + context, + clientObject.descriptionLocation ? clientObject.descriptionLocation : openApiTreeProvider.descriptionUrl, + clientObject.outputPath, + pluginTypes, + selectedPaths ? selectedPaths : clientObject.includePatterns, + [], + clientKey, + settings.clearCache, + settings.cleanOutput, + settings.disableValidationRules, + ConsumerOperation.Edit + ); + const duration = performance.now() - start; + const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; + reporter.sendRawTelemetryEvent(`${extensionId}.re-generatePlugin.completed`, { + "pluginType": pluginTypes.toString(), + "errorsCount": errorsCount.toString(), + }, { + "duration": duration, + }); + if (result) { + const isSuccess = await checkForSuccess(result); + if (!isSuccess) { + await exportLogsAndShowErrors(result); } + void vscode.window.showInformationMessage(`Plugin ${clientKey} re-generated successfully.`); } - ), - registerCommandWithTelemetry(reporter, - `${treeViewId}.pasteManifest`, - () => openManifestFromClipboard(openApiTreeProvider, "") - ) - ); + return result; + }); + openApiTreeProvider.resetInitialState(); + } // create a new status bar item that we can now manage kiotaStatusBarItem = vscode.window.createStatusBarItem( @@ -312,9 +573,9 @@ export async function activate( ); return; } - const existingLockFileUris = await vscode.workspace.findFiles(`**/${kiotaLockFile}`); - if (existingLockFileUris.length > 0) { - await Promise.all(existingLockFileUris.map(x => path.dirname(x.fsPath)).map(x => showUpgradeWarningMessage(x, context))); + const existingworkspaceFileUris = await vscode.workspace.findFiles(`**/${KIOTA_WORKSPACE_FILE}`); + if (existingworkspaceFileUris.length > 0) { + await Promise.all(existingworkspaceFileUris.map(x => path.dirname(x.fsPath)).map(x => showUpgradeWarningMessage(x, context))); } await updateStatusBarItem(context); try { @@ -351,41 +612,6 @@ export async function activate( context.subscriptions.push(disposable); } -async function openManifestFromClipboard(openApiTreeProvider: OpenApiTreeProvider, apiIdentifier?: string): Promise { - await openTreeViewWithProgress(async () => { - let clipBoardContent = await vscode.env.clipboard.readText(); - if (!clipBoardContent) { - await vscode.window.showErrorMessage( - vscode.l10n.t("No content found in the clipboard") - ); - return; - } - try { - let deserializedContent: ApiManifest; - try { - deserializedContent = JSON.parse(clipBoardContent) as ApiManifest; - // if it's valid json, it's not base64 encoded - } catch { - clipBoardContent = Buffer.from(clipBoardContent, 'base64').toString('utf-8'); - deserializedContent = JSON.parse(clipBoardContent) as ApiManifest; - } - if (!apiIdentifier && deserializedContent.apiDependencies && Object.keys(deserializedContent.apiDependencies).length > 1) { - const apiKeys = Object.keys(deserializedContent.apiDependencies); - const selectKeyResult = await selectApiManifestKey(apiKeys); - if (selectKeyResult.selectedKey) { - apiIdentifier = selectKeyResult.selectedKey; - } - } - } catch (error) { - await vscode.window.showErrorMessage( - vscode.l10n.t("Invalid content found in the clipboard") - ); - return; - } - const logs = await openApiTreeProvider.loadManifestFromContent(clipBoardContent, apiIdentifier); - await exportLogsAndShowErrors(logs); - }); -} function openTreeViewWithProgress(callback: () => Promise): Thenable { return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, @@ -408,26 +634,28 @@ function registerCommandWithTelemetry(reporter: TelemetryReporter, command: stri async function showUpgradeWarningMessage(clientPath: string, context: vscode.ExtensionContext): Promise { const kiotaVersion = context.extension.packageJSON.kiotaVersion.toLocaleLowerCase(); - const lockFilePath = path.join(clientPath, kiotaLockFile); - if(!fs.existsSync(lockFilePath)) { + const workspaceFilePath = path.join(clientPath, KIOTA_WORKSPACE_FILE); + if (!fs.existsSync(workspaceFilePath)) { return; } - const lockFileData = await vscode.workspace.fs.readFile(vscode.Uri.file(lockFilePath)); - const lockFile = JSON.parse(lockFileData.toString()) as {kiotaVersion: string}; - const clientVersion = lockFile.kiotaVersion.toLocaleLowerCase(); + const workspaceFileData = await vscode.workspace.fs.readFile(vscode.Uri.file(workspaceFilePath)); + const workspaceFile = JSON.parse(workspaceFileData.toString()) as { kiotaVersion: string }; + const clientVersion = workspaceFile.kiotaVersion.toLocaleLowerCase(); if (clientVersion.toLocaleLowerCase() !== kiotaVersion) { await vscode.window.showWarningMessage(vscode.l10n.t("Client will be upgraded from version {0} to {1}, upgrade your dependencies", clientVersion, kiotaVersion)); } } -async function loadLockFile(node: { fsPath: string }, openApiTreeProvider: OpenApiTreeProvider): Promise { - await openTreeViewWithProgress(() => openApiTreeProvider.loadLockFile(node.fsPath)); +async function loadWorkspaceFile(node: { fsPath: string }, openApiTreeProvider: OpenApiTreeProvider, clientOrPluginName?: string): Promise { + await openTreeViewWithProgress(() => openApiTreeProvider.loadWorkspaceFile(node.fsPath, clientOrPluginName)); + await updateTreeViewIcons(treeViewId, true); } -async function exportLogsAndShowErrors(result: KiotaLogEntry[]) : Promise { - const informationMessages = result - ? getLogEntriesForLevel(result, LogLevel.information) - : []; +async function loadEditPaths(clientOrPluginKey: string, clientObject: any, openApiTreeProvider: OpenApiTreeProvider): Promise { + await openTreeViewWithProgress(() => openApiTreeProvider.loadEditPaths(clientOrPluginKey, clientObject)); +} + +async function exportLogsAndShowErrors(result: KiotaLogEntry[]): Promise { const errorMessages = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error) : []; @@ -439,10 +667,6 @@ async function exportLogsAndShowErrors(result: KiotaLogEntry[]) : Promise await Promise.all(errorMessages.map((element) => { return vscode.window.showErrorMessage(element.message); })); - } else { - await Promise.all(informationMessages.map((element) => { - return vscode.window.showInformationMessage(element.message); - })); } } @@ -498,6 +722,17 @@ function getQueryParameters(uri: vscode.Uri): Record { }); return parameters; } +async function checkForSuccess(results: KiotaLogEntry[]) { + for (const result of results) { + if (result && result.message) { + if (result.message.includes("Generation completed successfully")) { + return true; + } + } + } + return false; +} + // This method is called when your extension is deactivated -export function deactivate() {} +export function deactivate() { } diff --git a/vscode/microsoft-kiota/src/generateClient.ts b/vscode/microsoft-kiota/src/generateClient.ts index 9bbbf56762..97475b8747 100644 --- a/vscode/microsoft-kiota/src/generateClient.ts +++ b/vscode/microsoft-kiota/src/generateClient.ts @@ -1,6 +1,7 @@ -import { connectToKiota, GenerationConfiguration, KiotaGenerationLanguage, KiotaLogEntry } from "./kiotaInterop"; +import { connectToKiota, ConsumerOperation, GenerationConfiguration, KiotaGenerationLanguage, KiotaLogEntry } from "./kiotaInterop"; import * as rpc from "vscode-jsonrpc/node"; import * as vscode from "vscode"; +import { getWorkspaceJsonDirectory } from "./util"; export function generateClient(context: vscode.ExtensionContext, descriptionPath: string, @@ -18,7 +19,10 @@ export function generateClient(context: vscode.ExtensionContext, serializers: string[], deserializers: string[], structuredMimeTypes: string[], - includeAdditionalData: boolean): Promise { + includeAdditionalData: boolean, + operation: ConsumerOperation, + workingDirectory: string = getWorkspaceJsonDirectory() +): Promise { return connectToKiota(context, async (connection) => { const request = new rpc.RequestType1( "Generate" @@ -42,7 +46,8 @@ export function generateClient(context: vscode.ExtensionContext, serializers: serializers, structuredMimeTypes: structuredMimeTypes, usesBackingStore: usesBackingStore, + operation: operation } as GenerationConfiguration, ); - }); + }, workingDirectory); }; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/generatePlugin.ts b/vscode/microsoft-kiota/src/generatePlugin.ts new file mode 100644 index 0000000000..8e9948bcf0 --- /dev/null +++ b/vscode/microsoft-kiota/src/generatePlugin.ts @@ -0,0 +1,38 @@ +import { connectToKiota, ConsumerOperation, GenerationConfiguration, KiotaGenerationLanguage, KiotaLogEntry, KiotaPluginType } from "./kiotaInterop"; +import * as rpc from "vscode-jsonrpc/node"; +import * as vscode from "vscode"; +import { getWorkspaceJsonDirectory } from "./util"; + +export function generatePlugin(context: vscode.ExtensionContext, + descriptionPath: string, + output: string, + pluginTypes: KiotaPluginType[], + includeFilters: string[], + excludeFilters: string[], + clientClassName: string, + clearCache: boolean, + cleanOutput: boolean, + disableValidationRules: string[], + operation: ConsumerOperation, + workingDirectory: string = getWorkspaceJsonDirectory() ): Promise { + return connectToKiota(context, async (connection) => { + const request = new rpc.RequestType1( + "GeneratePlugin" + ); + return await connection.sendRequest( + request, + { + pluginTypes: pluginTypes, + cleanOutput: cleanOutput, + clearCache: clearCache, + clientClassName: clientClassName, + disabledValidationRules: disableValidationRules, + excludePatterns: excludeFilters, + includePatterns: includeFilters, + openAPIFilePath: descriptionPath, + outputPath: output, + operation: operation + } as GenerationConfiguration, + ); + }, workingDirectory); +}; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/kiotaInterop.ts b/vscode/microsoft-kiota/src/kiotaInterop.ts index a7965067a5..3aea7cc663 100644 --- a/vscode/microsoft-kiota/src/kiotaInterop.ts +++ b/vscode/microsoft-kiota/src/kiotaInterop.ts @@ -2,12 +2,18 @@ import * as vscode from "vscode"; import * as cp from 'child_process'; import * as rpc from 'vscode-jsonrpc/node'; import { ensureKiotaIsPresent, getKiotaPath } from './kiotaInstall'; +import { getWorkspaceJsonDirectory } from "./util"; -export async function connectToKiota(context: vscode.ExtensionContext, callback:(connection: rpc.MessageConnection) => Promise): Promise { +export async function connectToKiota(context: vscode.ExtensionContext, callback:(connection: rpc.MessageConnection) => Promise, workingDirectory:string = getWorkspaceJsonDirectory()): Promise { const kiotaPath = getKiotaPath(context); await ensureKiotaIsPresent(context); const childProcess = cp.spawn(kiotaPath, ["rpc"],{ - cwd: vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0 ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined + cwd: workingDirectory, + env: { + ...process.env, + // eslint-disable-next-line @typescript-eslint/naming-convention + KIOTA_CONFIG_PREVIEW: "true", + } }); let connection = rpc.createMessageConnection( new rpc.StreamMessageReader(childProcess.stdout), @@ -36,6 +42,7 @@ export interface KiotaOpenApiNode { selected?: boolean, isOperation?: boolean; documentationUrl?: string; + clientNameOrPluginName?: string; } interface CacheClearableConfiguration { clearCache: boolean; @@ -100,6 +107,40 @@ export enum KiotaGenerationLanguage { // eslint-disable-next-line @typescript-eslint/naming-convention CLI = 8, } +export enum KiotaPluginType { + // eslint-disable-next-line @typescript-eslint/naming-convention + OpenAI = 0, + // eslint-disable-next-line @typescript-eslint/naming-convention + ApiManifest = 1, + // eslint-disable-next-line @typescript-eslint/naming-convention + ApiPlugin = 2, +} + +export enum ConsumerOperation { + // eslint-disable-next-line @typescript-eslint/naming-convention + Add, + // eslint-disable-next-line @typescript-eslint/naming-convention + Edit, + // eslint-disable-next-line @typescript-eslint/naming-convention + Remove, + // eslint-disable-next-line @typescript-eslint/naming-convention + Generate +} +export function parsePluginType(values: string[]): KiotaPluginType[] { + return values.map(value => { + switch (value.toLowerCase()) { + case "openai": + return KiotaPluginType.OpenAI; + case "apimanifest": + return KiotaPluginType.ApiManifest; + case "apiplugin": + return KiotaPluginType.ApiPlugin; + default: + throw new Error(`unknown plugin type: ${value}`); + } + }); +} + export function generationLanguageToString(language: KiotaGenerationLanguage): string { switch (language) { case KiotaGenerationLanguage.CSharp: @@ -217,23 +258,10 @@ export function maturityLevelToString(level: MaturityLevel): string { throw new Error("unknown level"); } } -export interface LockFile { - clientClassName: string; - clientNamespaceName: string; - descriptionHash: string; - descriptionLocation: string; - deserializers: string[]; - disabledValidationRules: string[]; - excludeBackwardCompatible: boolean; - excludePatterns: string[]; - includeAdditionalData: boolean; - includePatterns: string[]; - kiotaVersion: string; - language: string; - lockFileVersion: string; - serializers: string[]; - structuredMimeTypes: string[]; - usesBackingStore: boolean; +export interface ConfigurationFile { + version: string; + clients: Record; + plugins: Record; } export interface GenerationConfiguration { @@ -253,4 +281,29 @@ export interface GenerationConfiguration { serializers: string[]; structuredMimeTypes: string[]; usesBackingStore: boolean; -} \ No newline at end of file + pluginTypes: KiotaPluginType[]; + operation: ConsumerOperation; +} + +interface WorkspaceObjectProperties { + descriptionLocation: string; + includePatterns: string[]; + excludePatterns: string[]; + outputPath: string; +} + +export interface ClientObjectProperties extends WorkspaceObjectProperties { + language: string; + structuredMimeTypes: string[]; + clientNamespaceName: string; + usesBackingStore: boolean; + includeAdditionalData: boolean; + excludeBackwardCompatible: boolean; + disabledValidationRules: string[]; +} + +export interface PluginObjectProperties extends WorkspaceObjectProperties { + types: string[]; +} + +export type ClientOrPluginProperties = ClientObjectProperties | PluginObjectProperties; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/migrateFromLockFile.ts b/vscode/microsoft-kiota/src/migrateFromLockFile.ts new file mode 100644 index 0000000000..b1efb59f8a --- /dev/null +++ b/vscode/microsoft-kiota/src/migrateFromLockFile.ts @@ -0,0 +1,68 @@ +import { connectToKiota, KiotaLogEntry, LogLevel } from "./kiotaInterop"; +import * as rpc from "vscode-jsonrpc/node"; +import * as vscode from "vscode"; +import { KIOTA_LOCK_FILE } from "./constants"; +import { getWorkspaceJsonPath, handleMigration } from "./util"; + +export function migrateFromLockFile(context: vscode.ExtensionContext, lockFileDirectory: string): Promise { + return connectToKiota(context, async (connection) => { + const request = new rpc.RequestType1( + "MigrateFromLockFile" + ); + const result = await connection.sendRequest( + request, + lockFileDirectory + ); + return result; + }); +}; + +export async function checkForLockFileAndPrompt(context: vscode.ExtensionContext) { + const workspaceFolders = vscode.workspace.workspaceFolders; + + if(workspaceFolders) { + const lockFile = await vscode.workspace.findFiles(`{**/${KIOTA_LOCK_FILE},${KIOTA_LOCK_FILE}}`); + + if (lockFile.length > 0) { + const result = await vscode.window.showInformationMessage( + vscode.l10n.t("Please migrate your API clients to Kiota workspace."), + vscode.l10n.t("OK"), + vscode.l10n.t("Remind me later") + ); + + if (result === vscode.l10n.t("OK")) { + await handleMigration(context, workspaceFolders![0]); + await vscode.commands.executeCommand('kiota.workspace.refresh'); + } + } + } + }; + +export function displayMigrationMessages(logEntries: KiotaLogEntry[]) { + const workspaceJsonUri = vscode.Uri.file(getWorkspaceJsonPath()); + const successEntries = logEntries.filter(entry => + entry.level === LogLevel.information && entry.message.includes("migrated successfully") + ); + + if (successEntries.length > 0) { + successEntries.forEach(entry => { + vscode.window.showInformationMessage(vscode.l10n.t("API clients migrated successfully!")); + vscode.commands.executeCommand('kiota.workspace.refresh'); + vscode.commands.executeCommand('kiota.workspace.openWorkspaceFile', workspaceJsonUri); + }); + } else { + logEntries.forEach(entry => { + switch (entry.level) { + case LogLevel.warning: + vscode.window.showWarningMessage(vscode.l10n.t(entry.message)); + break; + case LogLevel.error: + case LogLevel.critical: + vscode.window.showErrorMessage(vscode.l10n.t(entry.message)); + break; + default: + break; + } + }); + } +} \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/openApiTreeProvider.ts b/vscode/microsoft-kiota/src/openApiTreeProvider.ts index 881be00ba2..0ee2cc8283 100644 --- a/vscode/microsoft-kiota/src/openApiTreeProvider.ts +++ b/vscode/microsoft-kiota/src/openApiTreeProvider.ts @@ -3,41 +3,106 @@ import * as os from 'os'; import * as path from 'path'; import * as vscode from 'vscode'; import * as rpc from 'vscode-jsonrpc/node'; -import { connectToKiota, KiotaGetManifestDetailsConfiguration, KiotaLogEntry, KiotaManifestResult, KiotaOpenApiNode, KiotaShowConfiguration, KiotaShowResult, LockFile } from './kiotaInterop'; +import * as crypto from 'crypto'; +import { + ClientObjectProperties, + ClientOrPluginProperties, + connectToKiota, + KiotaGetManifestDetailsConfiguration, + KiotaLogEntry, + KiotaManifestResult, + KiotaOpenApiNode, + KiotaShowConfiguration, + KiotaShowResult, + ConfigurationFile, + PluginObjectProperties } from './kiotaInterop'; import { ExtensionSettings } from './extensionSettings'; +import { treeViewId } from './constants'; +import { updateTreeViewIcons } from './util'; export class OpenApiTreeProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; private apiTitle?: string; + private initialStateHash: string = ''; constructor( private readonly context: vscode.ExtensionContext, - private readonly settingsGetter:() => ExtensionSettings, + private readonly settingsGetter: () => ExtensionSettings, private _descriptionUrl?: string, public includeFilters: string[] = [], public excludeFilters: string[] = []) { - - } - private _lockFilePath?: string; - private _lockFile?: LockFile; - public get isLockFileLoaded(): boolean { - return !!this._lockFile; - } - public async loadLockFile(path: string): Promise { - this.closeDescription(false); - this._lockFilePath = path; - const lockFileData = await vscode.workspace.fs.readFile(vscode.Uri.file(path)); - this._lockFile = JSON.parse(lockFileData.toString()) as LockFile; - if (this._lockFile?.descriptionLocation) { - this._descriptionUrl = this._lockFile.descriptionLocation; - this.includeFilters = this._lockFile.includePatterns; - this.excludeFilters = this._lockFile.excludePatterns; - const settings = this.settingsGetter(); - await this.loadNodes(settings.clearCache); - if (this.rawRootNode) { - this.refreshView(); + + } + private _workspaceFilePath?: string; + private _workspaceFile?: ConfigurationFile | Partial = {}; + public get isWorkspaceFileLoaded(): boolean { + return !!this._workspaceFile; + } + public async loadWorkspaceFile(path: string, clientOrPluginName?: string): Promise { + this.closeDescription(false); + this._workspaceFilePath = path; + const workspaceFileData = await vscode.workspace.fs.readFile(vscode.Uri.file(path)); + let parsedWorkspaceFile = JSON.parse(workspaceFileData.toString()) as ConfigurationFile; + + if (clientOrPluginName) { + let filteredData: Partial = { version: parsedWorkspaceFile.version }; + + if (parsedWorkspaceFile.clients && parsedWorkspaceFile.clients[clientOrPluginName]) { + filteredData.clients = { + [clientOrPluginName]: parsedWorkspaceFile.clients[clientOrPluginName] + }; + } + + if (parsedWorkspaceFile.plugins && parsedWorkspaceFile.plugins[clientOrPluginName]) { + filteredData.plugins = { + [clientOrPluginName]: parsedWorkspaceFile.plugins[clientOrPluginName] + }; + } + + parsedWorkspaceFile = filteredData as ConfigurationFile; + } + + this._workspaceFile = parsedWorkspaceFile; + + const clientOrPlugin: ClientOrPluginProperties | undefined = + Object.values(this._workspaceFile.clients ?? {})[0] || + Object.values(this._workspaceFile.plugins ?? {})[0]; + + if (clientOrPlugin) { + this._descriptionUrl = clientOrPlugin.descriptionLocation; + this.includeFilters = clientOrPlugin.includePatterns; + this.excludeFilters = clientOrPlugin.excludePatterns; + + const settings = this.settingsGetter(); + await this.loadNodes(settings.clearCache, clientOrPluginName); + + if (this.rawRootNode) { + this.refreshView(); + } + } + } + public async loadEditPaths(clientOrPluginKey: string, clientObject: ClientOrPluginProperties): Promise { + this.closeDescription(false); + const newWorkspaceFile: ConfigurationFile = { version: '1.0.0', clients: {}, plugins: {} }; + + if ((clientObject as ClientObjectProperties).clientNamespaceName) { + newWorkspaceFile.clients[clientOrPluginKey] = clientObject as ClientObjectProperties; + } else { + newWorkspaceFile.plugins[clientOrPluginKey] = clientObject as PluginObjectProperties; + } + this._workspaceFile = newWorkspaceFile; + if (clientObject.descriptionLocation) { + this._descriptionUrl = clientObject.descriptionLocation; + this.includeFilters = clientObject.includePatterns; + this.excludeFilters = clientObject.excludePatterns; + + const settings = this.settingsGetter(); + await this.loadNodes(settings.clearCache, clientOrPluginKey); + + if (this.rawRootNode) { + this.refreshView(); + } } - } } public async loadManifestFromUri(path: string, apiIdentifier?: string): Promise { this.closeDescription(false); @@ -58,34 +123,58 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider this.setAllSelected(x, selected)); } + private getFirstClient(): ClientObjectProperties | undefined { + return this._workspaceFile?.clients ? Object.values(this._workspaceFile.clients)[0] : undefined; + } public get outputPath(): string { - return this._lockFilePath ? path.parse(this._lockFilePath).dir : ''; + return this._workspaceFilePath ? path.parse(this._workspaceFilePath).dir : ''; } public get clientClassName(): string { - return this._lockFile?.clientClassName ?? ''; + if (this._workspaceFile?.clients) { + const client = this.getFirstClient(); + return client ? client.clientNamespaceName : ''; + } + return ''; } + public get clientNamespaceName(): string { - return this._lockFile?.clientNamespaceName ?? ''; + if (this._workspaceFile?.clients) { + const client = this.getFirstClient(); + return client ? client.clientNamespaceName : ''; + } + return ''; } + public get language(): string { - return this._lockFile?.language ?? ''; + if (this._workspaceFile?.clients) { + const client = this.getFirstClient(); + return client ? client.language : ''; + } + return ''; } public closeDescription(shouldRefresh = true) { this._descriptionUrl = ''; this.rawRootNode = undefined; - this._lockFile = undefined; - this._lockFilePath = undefined; + this._workspaceFile = undefined; + this._workspaceFilePath = undefined; this.tokenizedFilter = []; this._filterText = ''; + this.includeFilters = []; + this.excludeFilters = []; if (shouldRefresh) { this.refreshView(); } + void updateTreeViewIcons(treeViewId, false); + } + public isEmpty(): boolean { + return this.rawRootNode === undefined; } public async setDescriptionUrl(descriptionUrl: string): Promise { this.closeDescription(false); this._descriptionUrl = descriptionUrl; const settings = this.settingsGetter(); await this.loadNodes(settings.clearCache); + this.initialStateHash = this.hashDescription(this.rawRootNode); this.refreshView(); } public get descriptionUrl(): string { @@ -96,7 +185,7 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider this.selectInternal(x, selected, recursive)); } else if (!isOperationNode) { apiNode.children.filter(x => x.isOperation ?? false).forEach(x => this.selectInternal(x, selected, false)); @@ -121,7 +210,15 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider x.segment === segment); + let child: KiotaOpenApiNode | undefined; + if (currentNode.clientNameOrPluginName) { + const rootChild = currentNode.children.find(x => x.segment === '/'); + if (rootChild) { + child = rootChild.children.find(x => x.segment === segment); + } + } else { + child = currentNode.children.find(x => x.segment === segment); + } if (child) { return this.findApiNode(segments, child); } else if (segment.startsWith('{') && segment.endsWith('}')) { @@ -135,6 +232,23 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider { + private async loadNodes(clearCache: boolean, clientNameOrPluginName?: string): Promise { if (!this.descriptionUrl || this.descriptionUrl.length === 0) { return; } @@ -207,19 +321,34 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider this.getTreeNodeFromKiotaNode(x)), - node.documentationUrl + node.documentationUrl, + node.clientNameOrPluginName ); } getChildren(element?: OpenApiTreeNode): vscode.ProviderResult { @@ -254,10 +385,31 @@ function getPathSegments(path: string): string[] { function trimOperation(path: string): string { return path.split(operationSeparator)[0]; } + +function createKiotaOpenApiNode( + segment: string, + path: string, + children: KiotaOpenApiNode[] = [], + selected?: boolean, + isOperation?: boolean, + documentationUrl?: string, + clientNameOrPluginName?: string +): KiotaOpenApiNode { + return { + segment, + path, + children, + selected, + isOperation, + documentationUrl, + clientNameOrPluginName + }; +} type IconSet = string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri } | vscode.ThemeIcon; export class OpenApiTreeNode extends vscode.TreeItem { private static readonly selectedSet: IconSet = new vscode.ThemeIcon('check'); private static readonly unselectedSet: IconSet = new vscode.ThemeIcon('circle-slash'); + constructor( public readonly path: string, public readonly label: string, @@ -265,13 +417,19 @@ export class OpenApiTreeNode extends vscode.TreeItem { public readonly collapsibleState: vscode.TreeItemCollapsibleState, private readonly isOperation: boolean, filterTokens: string[], + apiTitle: string | undefined, public readonly children: OpenApiTreeNode[] = [], public readonly documentationUrl?: string, + public readonly clientNameOrPluginName?: string ) { super(label, collapsibleState); this.id = `${path}_${filterTokens.join('_')}`; // so the collapsed state is NOT persisted between filter changes - this.contextValue = documentationUrl; + this.contextValue = label === pathSeparator + " (" + apiTitle + ")" ? 'apiTitle' : (this.documentationUrl ? 'documentationUrl' : ''); this.iconPath = selected ? OpenApiTreeNode.selectedSet : OpenApiTreeNode.unselectedSet; + if (clientNameOrPluginName) { + this.label = clientNameOrPluginName; + this.contextValue = 'clientNameOrPluginName'; + } } public isNodeVisible(tokenizedFilter: string[]): boolean { if (tokenizedFilter.length === 0) { @@ -286,7 +444,8 @@ export class OpenApiTreeNode extends vscode.TreeItem { return true; } - const segments = getPathSegments(splatPath); + // "tokenizedFilter" is lowercased so ensure the same is DOM for the path segments for proper matching + const segments = getPathSegments(splatPath).map(x => x.trim().toLowerCase()); return tokenizedFilter.some(x => segments.some(s => s.includes(x))) || this.children.some(x => x.isNodeVisible(tokenizedFilter)); diff --git a/vscode/microsoft-kiota/src/steps.ts b/vscode/microsoft-kiota/src/steps.ts index dc3c0c3cf2..4a0788ebe1 100644 --- a/vscode/microsoft-kiota/src/steps.ts +++ b/vscode/microsoft-kiota/src/steps.ts @@ -1,100 +1,8 @@ -import { QuickPickItem, window, Disposable, QuickInputButton, QuickInput, QuickInputButtons, workspace, l10n, Uri } from 'vscode'; +import * as vscode from 'vscode'; +import { QuickPickItem, window, Disposable, QuickInputButton, QuickInput, QuickInputButtons, workspace, l10n, Uri, OpenDialogOptions } from 'vscode'; import { allGenerationLanguages, generationLanguageToString, KiotaSearchResultItem, LanguagesInformation, maturityLevelToString } from './kiotaInterop'; -import { kiotaLockFile } from './extension'; - - -export async function openSteps() { - const state = {} as Partial; - const title = l10n.t('Open an API description'); - let step = 1; - let totalSteps = 1; - async function inputPathOrUrl(input: MultiStepInput, state: Partial) { - state.descriptionPath = await input.showInputBox({ - title, - step: step++, - totalSteps: totalSteps, - value: state.descriptionPath || '', - prompt: l10n.t('A path or url to an OpenAPI description'), - validate: validateIsNotEmpty, - shouldResume: shouldResume - }); - } - await MultiStepInput.run(input => inputPathOrUrl(input, state), () => step-=2); - return state; -}; - -export async function openManifestSteps() { - const state = {} as Partial; - const title = l10n.t('Open an API manifest'); - let step = 1; - let totalSteps = 1; - async function inputPathOrUrl(input: MultiStepInput, state: Partial) { - state.manifestPath = await input.showInputBox({ - title, - step: step++, - totalSteps: totalSteps, - value: state.manifestPath || '', - prompt: l10n.t('A path or URL to an API manifest'), - validate: validateIsNotEmpty, - shouldResume: shouldResume - }); - } - await MultiStepInput.run(input => inputPathOrUrl(input, state), () => step-=2); - return state; -}; - -export async function selectApiManifestKey(keys: string[]) { - const state = {} as Partial; - let step = 1; - let totalSteps = 1; - const title = l10n.t('Select an API manifest key'); - async function pickSearchResult(input: MultiStepInput, state: Partial) { - const items = keys.map(x => - { - return { - label: x, - } as QuickPickItem; - }); - const pick = await input.showQuickPick({ - title, - step: step++, - totalSteps: totalSteps, - placeholder: l10n.t('Select an API manifest key'), - items: items, - shouldResume: shouldResume - }); - state.selectedKey = keys.find(x => x === pick?.label); - } - await MultiStepInput.run(input => pickSearchResult(input, state), () => step-=2); - return state; -} - -export async function searchLockSteps() { - const state = {} as Partial; - let step = 1; - let totalSteps = 1; - const title = l10n.t('Open a lock file'); - async function pickSearchResult(input: MultiStepInput, state: Partial) { - const searchResults = await workspace.findFiles(`**/${kiotaLockFile}`); - const items = searchResults.map(x => - { - return { - label: x.path.replace(workspace.getWorkspaceFolder(x)?.uri.path || '', ''), - } as QuickPickItem; - }); - const pick = await input.showQuickPick({ - title, - step: step++, - totalSteps: totalSteps, - placeholder: l10n.t('Pick a lock file'), - items: items, - shouldResume: shouldResume - }); - state.lockFilePath = searchResults.find(x => x.path.replace(workspace.getWorkspaceFolder(x)?.uri.path || '', '') === pick?.label); - } - await MultiStepInput.run(input => pickSearchResult(input, state), () => step-=2); - return state; -} +import { findAppPackageDirectory, getWorkspaceJsonDirectory } from './util'; +import * as path from 'path'; export async function filterSteps(existingFilter: string, filterCallback: (searchQuery: string) => void) { const state = {} as Partial; @@ -116,35 +24,82 @@ export async function filterSteps(existingFilter: string, filterCallback: (searc shouldResume: shouldResume }); } - await MultiStepInput.run(input => inputFilterQuery(input, state), () => step-=2); + await MultiStepInput.run(input => inputFilterQuery(input, state), () => step -= 2); return state; } export async function searchSteps(searchCallBack: (searchQuery: string) => Thenable | undefined>) { - const state = {} as Partial; - const title = l10n.t('Search for an API description'); + const state: Partial = {}; + const title = l10n.t('Add an API description'); let step = 1; let totalSteps = 2; - async function inputSearchQuery(input: MultiStepInput, state: Partial) { - state.searchQuery = await input.showInputBox({ + async function inputPathOrSearch(input: MultiStepInput, state: Partial) { + const selectedOption = await input.showQuickPick({ title, step: step++, totalSteps: totalSteps, - value: state.searchQuery || '', - prompt: l10n.t('Enter a search query'), + placeholder: l10n.t('Search or browse a path to an API description'), + items: [{ label: l10n.t('Search') }, { label: l10n.t('Browse path') }], validate: validateIsNotEmpty, shouldResume: shouldResume }); + if (selectedOption?.label === l10n.t('Search')) { + return (input: MultiStepInput) => inputSearch(input, state); + } + else if (selectedOption?.label === l10n.t('Browse path')) { + const fileUri = await input.showOpenDialog({ + canSelectMany: false, + openLabel: 'Select', + canSelectFolders: false, + canSelectFiles: true + }); + + if (fileUri && fileUri[0]) { + state.descriptionPath = fileUri[0].fsPath; + } + } + } + async function inputSearch(input: MultiStepInput, state: Partial) { + state.searchQuery = await input.showInputBox({ + title, + step: step++, + totalSteps: totalSteps, + value: state.searchQuery ?? '', + prompt: l10n.t('Search or paste a path to an API description'), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); state.searchResults = await searchCallBack(state.searchQuery); - return (input: MultiStepInput) => pickSearchResult(input, state); + if (state.searchResults && Object.keys(state.searchResults).length > 0) { + return (input: MultiStepInput) => pickSearchResult(input, state); + } else { + state.descriptionPath = state.searchQuery; + return (input: MultiStepInput) => inputPathOrUrl(input, state); + } + } + + async function inputPathOrUrl(input: MultiStepInput, state: Partial) { + if (state.descriptionPath) { + return; + } + state.descriptionPath = await input.showInputBox({ + title, + step: step++, + totalSteps: 1, + value: state.descriptionPath || '', + prompt: l10n.t('Search or paste a path to an API description'), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); } - async function pickSearchResult(input: MultiStepInput, state: Partial) { + + async function pickSearchResult(input: MultiStepInput, state: Partial) { const items: QuickSearchPickItem[] = []; - if(state.searchResults) { + if (state.searchResults) { for (const key of Object.keys(state.searchResults)) { const value = state.searchResults[key]; - items.push({label: key, description: value.Description, descriptionUrl: value.DescriptionUrl}); + items.push({ label: key, description: value.Description, descriptionUrl: value.DescriptionUrl }); } } const pick = await input.showQuickPick({ @@ -157,68 +112,137 @@ export async function searchSteps(searchCallBack: (searchQuery: string) => Thena }); state.descriptionPath = items.find(x => x.label === pick?.label)?.descriptionUrl || ''; } - await MultiStepInput.run(input => inputSearchQuery(input, state), () => step-=2); + await MultiStepInput.run(input => inputPathOrSearch(input, state), () => step -= 2); return state; } -interface SearchItem { - descriptionUrl?: string; -} -type QuickSearchPickItem = QuickPickItem & SearchItem; export async function generateSteps(existingConfiguration: Partial, languagesInformation?: LanguagesInformation) { - const state = {...existingConfiguration} as Partial; - if (existingConfiguration.clientClassName && existingConfiguration.clientNamespaceName && existingConfiguration.outputPath && existingConfiguration.language && - typeof existingConfiguration.clientNamespaceName === 'string' && typeof existingConfiguration.outputPath === 'string' && typeof existingConfiguration.language === 'string' && - existingConfiguration.clientClassName.length > 0 && existingConfiguration.clientNamespaceName.length > 0 && existingConfiguration.outputPath.length > 0 && existingConfiguration.language.length > 0) { + const state = { ...existingConfiguration } as Partial; + if (existingConfiguration.generationType && existingConfiguration.clientClassName && existingConfiguration.clientNamespaceName && existingConfiguration.outputPath && existingConfiguration.language && + typeof existingConfiguration.generationType === 'string' && existingConfiguration.clientNamespaceName === 'string' && typeof existingConfiguration.outputPath === 'string' && typeof existingConfiguration.language === 'string' && + existingConfiguration.generationType.length > 0 && existingConfiguration.clientClassName.length > 0 && existingConfiguration.clientNamespaceName.length > 0 && existingConfiguration.outputPath.length > 0 && existingConfiguration.language.length > 0) { return state; } - if(typeof state.outputPath === 'string') { + if (typeof state.outputPath === 'string') { state.outputPath = workspace.asRelativePath(state.outputPath); } - const title = l10n.t('Generate an API client'); + const workspaceOpen = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0; + + let workspaceFolder = getWorkspaceJsonDirectory(); + const appPackagePath = findAppPackageDirectory(workspaceFolder); + if (appPackagePath) { + workspaceFolder = appPackagePath; + } + let step = 1; let totalSteps = 4; + + const folderSelectionOption = l10n.t('Browse your output directory'); + let inputOptions = [ + { label: l10n.t('Default folder'), description: workspaceFolder }, + { label: folderSelectionOption } + ]; + + function updateWorkspaceFolder(name: string | undefined) { + if (name && (!workspaceOpen)) { + workspaceFolder = getWorkspaceJsonDirectory(name); + inputOptions = [ + { label: l10n.t('Default folder'), description: workspaceFolder }, + { label: folderSelectionOption } + ]; + } + } + async function inputGenerationType(input: MultiStepInput, state: Partial) { + const items = [l10n.t('Generate an API client'), l10n.t('Generate a plugin'), l10n.t('Generate an API manifest')]; + const option = await input.showQuickPick({ + title: l10n.t('What do you want to generate?'), + step: 1, + totalSteps: 1, + placeholder: l10n.t('Select an option'), + items: items.map(x => ({ label: x })), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); + if (option.label === l10n.t('Generate an API client')) { + state.generationType = "client"; + return (input: MultiStepInput) => inputClientClassName(input, state); + } + else if (option.label === l10n.t('Generate a plugin')) { + state.generationType = "plugin"; + return (input: MultiStepInput) => inputPluginName(input, state); + } + else if (option.label === l10n.t('Generate an API manifest')) { + state.generationType = "apimanifest"; + return (input: MultiStepInput) => inputManifestName(input, state); + } + } async function inputClientClassName(input: MultiStepInput, state: Partial) { - state.clientClassName = await input.showInputBox({ - title, - step: step++, - totalSteps: totalSteps, - value: state.clientClassName || '', + state.clientClassName = await input.showInputBox({ + title: `${l10n.t('Create a new API client')} - ${l10n.t('class')}`, + step: step++, + totalSteps: totalSteps, + value: state.clientClassName ?? '', placeholder: 'ApiClient', - prompt: l10n.t('Choose a name for the client class'), - validate: validateIsNotEmpty, - shouldResume: shouldResume - }); - return (input: MultiStepInput) => inputClientNamespaceName(input, state); - } + prompt: l10n.t('Choose a name for the client class'), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); + updateWorkspaceFolder(state.clientClassName); + return (input: MultiStepInput) => inputClientNamespaceName(input, state); + } async function inputClientNamespaceName(input: MultiStepInput, state: Partial) { - state.clientNamespaceName = await input.showInputBox({ - title, - step: step++, - totalSteps: totalSteps, - value: typeof state.clientNamespaceName === 'string' ? state.clientNamespaceName : '', - placeholder: 'ApiSDK', - prompt: l10n.t('Choose a name for the client class namespace'), - validate: validateIsNotEmpty, - shouldResume: shouldResume - }); - return (input: MultiStepInput) => inputOutputPath(input, state); - } + state.clientNamespaceName = await input.showInputBox({ + title: `${l10n.t('Create a new API client')} - ${l10n.t('namespace')}`, + step: step++, + totalSteps: totalSteps, + value: typeof state.clientNamespaceName === 'string' ? state.clientNamespaceName : '', + placeholder: 'ApiSDK', + prompt: l10n.t('Choose a name for the client class namespace'), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); + return (input: MultiStepInput) => inputOutputPath(input, state); + } async function inputOutputPath(input: MultiStepInput, state: Partial) { - state.outputPath = await input.showInputBox({ - title, - step: step++, - totalSteps: totalSteps, - value: typeof state.outputPath === 'string' ? state.outputPath : '', - placeholder: 'myproject/apiclient', - prompt: l10n.t('Enter an output path relative to the root of the project'), - validate: validateIsNotEmpty, - shouldResume: shouldResume - }); - return (input: MultiStepInput) => pickLanguage(input, state); - } + while (true) { + const selectedOption = await input.showQuickPick({ + title: `${l10n.t('Create a new API client')} - ${l10n.t('output directory')}`, + step: 4, + totalSteps: totalSteps, + placeholder: l10n.t('Enter an output path relative to the root of the project'), + items: inputOptions, + shouldResume: shouldResume + }); + if (selectedOption) { + if (selectedOption?.label === folderSelectionOption) { + const folderUri = await input.showOpenDialog({ + canSelectMany: false, + openLabel: 'Select', + canSelectFolders: true, + canSelectFiles: false + }); + + if (folderUri && folderUri[0]) { + state.outputPath = folderUri[0].fsPath; + } else { + continue; + } + } else { + state.outputPath = selectedOption.description; + if (workspaceOpen) { + state.workingDirectory = vscode.workspace.workspaceFolders![0].uri.fsPath; + } else { + state.workingDirectory = path.dirname(selectedOption.description!); + } + } + } + state.outputPath = state.outputPath === '' ? 'output' : state.outputPath; + return (input: MultiStepInput) => pickLanguage(input, state); + } + + } async function pickLanguage(input: MultiStepInput, state: Partial) { const items = allGenerationLanguages.map(x => { const lngName = generationLanguageToString(x); @@ -227,20 +251,141 @@ export async function generateSteps(existingConfiguration: Partial x.languageName === state.language) : undefined, + shouldResume: shouldResume + }); + state.language = pick.label.split('-')[0].trim(); + } + async function inputPluginName(input: MultiStepInput, state: Partial) { + state.pluginName = await input.showInputBox({ + title: `${l10n.t('Create a new plugin')} - ${l10n.t('plugin name')}`, + step: step++, + totalSteps: 3, + value: state.pluginName ?? '', + placeholder: 'MyPlugin', + prompt: l10n.t('Choose a name for the plugin'), + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); + updateWorkspaceFolder(state.pluginName); + return (input: MultiStepInput) => inputPluginType(input, state); + } + async function inputPluginType(input: MultiStepInput, state: Partial) { + const items = ['API Plugin', 'Open AI'].map(x => ({ label: x }) as QuickPickItem); + const pluginTypes = await input.showQuickPick({ + title: l10n.t('Choose a plugin type'), + step: step++, + totalSteps: 3, + placeholder: l10n.t('Select an option'), + items: items, + validate: validateIsNotEmpty, + shouldResume: shouldResume + }); + pluginTypes.label === 'API Plugin' ? state.pluginTypes = ['ApiPlugin'] : state.pluginTypes = ['OpenAI']; + return (input: MultiStepInput) => inputPluginOutputPath(input, state); + } + async function inputPluginOutputPath(input: MultiStepInput, state: Partial) { + while (true) { + const selectedOption = await input.showQuickPick({ + title: `${l10n.t('Create a new plugin')} - ${l10n.t('output directory')}`, + step: 3, + totalSteps: 3, + placeholder: l10n.t('Enter an output path relative to the root of the project'), + items: inputOptions, + shouldResume: shouldResume + }); + if (selectedOption) { + if (selectedOption?.label === folderSelectionOption) { + const folderUri = await input.showOpenDialog({ + canSelectMany: false, + openLabel: 'Select', + canSelectFolders: true, + canSelectFiles: false + }); + + if (folderUri && folderUri[0]) { + state.outputPath = folderUri[0].fsPath; + } else { + continue; + } + } else { + state.outputPath = selectedOption.description; + if (workspaceOpen) { + state.workingDirectory = vscode.workspace.workspaceFolders![0].uri.fsPath; + } else { + state.workingDirectory = path.dirname(selectedOption.description!); + } + } + } + state.outputPath = state.outputPath === '' ? 'output' : state.outputPath; + break; + } + } + + async function inputManifestName(input: MultiStepInput, state: Partial) { + state.pluginName = await input.showInputBox({ + title: `${l10n.t('Create a new manifest')} - ${l10n.t('manifest name')}`, + step: step++, + totalSteps: 3, + value: state.pluginName ?? '', + placeholder: 'MyManifest', + prompt: l10n.t('Choose a name for the manifest'), + validate: validateIsNotEmpty, + shouldResume: shouldResume }); - const pick = await input.showQuickPick({ - title, - step: step++, - totalSteps: totalSteps, - placeholder: l10n.t('Pick a language'), - items, - activeItem: typeof state.language === 'string' ? items.find(x => x.languageName === state.language) : undefined, - shouldResume: shouldResume - }); - state.language = pick.label.split('-')[0].trim(); - } - await MultiStepInput.run(input => inputClientClassName(input, state), () => step-=2); + updateWorkspaceFolder(state.pluginName); + return (input: MultiStepInput) => inputManifestOutputPath(input, state); + } + async function inputManifestOutputPath(input: MultiStepInput, state: Partial) { + while (true) { + const selectedOption = await input.showQuickPick({ + title: `${l10n.t('Create a new manifest')} - ${l10n.t('output directory')}`, + step: 2, + totalSteps: 3, + placeholder: l10n.t('Enter an output path relative to the root of the project'), + items: inputOptions, + shouldResume: shouldResume + }); + if (selectedOption) { + if (selectedOption?.label === folderSelectionOption) { + const folderUri = await input.showOpenDialog({ + canSelectMany: false, + openLabel: 'Select', + canSelectFolders: true, + canSelectFiles: false + }); + + if (folderUri && folderUri[0]) { + state.outputPath = folderUri[0].fsPath; + } else { + continue; + } + } else { + state.outputPath = selectedOption.description; + if (workspaceOpen) { + state.workingDirectory = vscode.workspace.workspaceFolders![0].uri.fsPath; + } else { + state.workingDirectory = path.dirname(selectedOption.description!); + } + } + } + state.outputPath === '' ? state.outputPath = 'output' : state.outputPath; + break; + } + + } + await MultiStepInput.run(input => inputGenerationType(input, state), () => step -= 2); + if (!state.workingDirectory) { + state.workingDirectory = workspaceOpen ? vscode.workspace.workspaceFolders![0].uri.fsPath : state.outputPath as string; + } return state; } @@ -252,7 +397,7 @@ function shouldResume() { } function validateIsNotEmpty(value: string) { - return Promise.resolve(value.length > 0 ? undefined : 'Required'); + return Promise.resolve(value.length > 0 ? undefined : l10n.t('Required')); } interface BaseStepsState { @@ -271,200 +416,252 @@ interface OpenState extends BaseStepsState { descriptionPath: string; } -interface OpenManifestState extends BaseStepsState { - manifestPath: string; -} - -interface SearchLockState extends BaseStepsState { - lockFilePath: Uri; -} - -interface SelectApiManifestKey extends BaseStepsState { - selectedKey: string; +interface SearchItem { + descriptionUrl?: string; } +type QuickSearchPickItem = QuickPickItem & SearchItem; -interface GenerateState extends BaseStepsState { +export interface GenerateState extends BaseStepsState { + generationType: QuickPickItem | string; + pluginTypes: QuickPickItem | string[]; + pluginName: string; clientClassName: string; clientNamespaceName: QuickPickItem | string; language: QuickPickItem | string; outputPath: QuickPickItem | string; + workingDirectory: string; +} +export enum GenerationType { + // eslint-disable-next-line @typescript-eslint/naming-convention + Client = 0, + // eslint-disable-next-line @typescript-eslint/naming-convention + Plugin = 1, + // eslint-disable-next-line @typescript-eslint/naming-convention + ApiManifest = 2, +} +export function parseGenerationType(generationType: string | QuickPickItem | undefined): GenerationType { + if (typeof generationType !== 'string') { + throw new Error('generationType has not been selected yet'); + } + switch (generationType) { + case "client": + return GenerationType.Client; + case "plugin": + return GenerationType.Plugin; + case "apimanifest": + return GenerationType.ApiManifest; + default: + throw new Error(`Unknown generation type ${generationType}`); + } } class InputFlowAction { - static back = new InputFlowAction(); - static cancel = new InputFlowAction(); - static resume = new InputFlowAction(); + static back = new InputFlowAction(); + static cancel = new InputFlowAction(); + static resume = new InputFlowAction(); } type InputStep = (input: MultiStepInput) => Thenable; interface QuickPickParameters { - title: string; - step: number; - totalSteps: number; - items: T[]; - activeItem?: T; - ignoreFocusOut?: boolean; - placeholder: string; - buttons?: QuickInputButton[]; - shouldResume: () => Thenable; + title: string; + step: number; + totalSteps: number; + items: T[]; + activeItem?: T; + ignoreFocusOut?: boolean; + placeholder: string; + buttons?: QuickInputButton[]; + shouldResume: () => Thenable; } interface InputBoxParameters { - title: string; - step: number; - totalSteps: number; - value: string; - prompt: string; - validate: (value: string) => Promise; - buttons?: QuickInputButton[]; - ignoreFocusOut?: boolean; - placeholder?: string; - shouldResume: () => Thenable; + title: string; + step: number; + totalSteps: number; + value: string; + prompt: string; + validate?: (value: string) => Promise; + buttons?: QuickInputButton[]; + ignoreFocusOut?: boolean; + placeholder?: string; + shouldResume: () => Thenable; +} +interface OpenDialogParameters { + canSelectMany: boolean; + openLabel: string; + canSelectFolders: boolean; + canSelectFiles: boolean; } class MultiStepInput { + async showOpenDialog({ canSelectMany, openLabel, canSelectFolders, canSelectFiles }: OpenDialogParameters): Promise { + const disposables: Disposable[] = []; + + try { + return await new Promise((resolve) => { + const input: OpenDialogOptions = { + canSelectMany, + openLabel, + canSelectFolders, + canSelectFiles + }; + + void window.showOpenDialog(input).then(folderUris => { + if (folderUris && folderUris.length > 0) { + resolve([folderUris[0]]); + } else { + resolve(undefined); + } + }); + }); + } finally { + disposables.forEach(d => d.dispose()); + } + } + + static async run(start: InputStep, onNavBack?: () => void) { + const input = new MultiStepInput(); + return input.stepThrough(start, onNavBack); + } - static async run(start: InputStep, onNavBack?: () => void) { - const input = new MultiStepInput(); - return input.stepThrough(start, onNavBack); - } - - private current?: QuickInput; - private steps: InputStep[] = []; - - private async stepThrough(start: InputStep, onNavBack?: () => void) { - let step: InputStep | void = start; - while (step) { - this.steps.push(step); - if (this.current) { - this.current.enabled = false; - this.current.busy = true; - } - try { - step = await step(this); - } catch (err) { - if (err === InputFlowAction.back) { + private current?: QuickInput; + private steps: InputStep[] = []; + + private async stepThrough(start: InputStep, onNavBack?: () => void) { + let step: InputStep | void = start; + while (step) { + this.steps.push(step); + if (this.current) { + this.current.enabled = false; + this.current.busy = true; + } + try { + step = await step(this); + } catch (err) { + if (err === InputFlowAction.back) { if (onNavBack) { onNavBack(); } - this.steps.pop(); - step = this.steps.pop(); - } else if (err === InputFlowAction.resume) { - step = this.steps.pop(); - } else if (err === InputFlowAction.cancel) { - step = undefined; - } else { - throw err; - } - } - } - if (this.current) { - this.current.dispose(); - } - } - - async showQuickPick>({ title, step, totalSteps, items, activeItem, ignoreFocusOut, placeholder, buttons, shouldResume }: P) { - const disposables: Disposable[] = []; - try { - return await new Promise((resolve, reject) => { - const input = window.createQuickPick(); - input.title = title; - input.step = step; - input.totalSteps = totalSteps; - input.ignoreFocusOut = ignoreFocusOut ?? false; - input.placeholder = placeholder; - input.items = items; - input.buttons = [ - ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), - ...(buttons || []) - ]; - disposables.push( - input.onDidTriggerButton(item => { - if (item === QuickInputButtons.Back) { - reject(InputFlowAction.back); - } else { - resolve(item); - } - }), - input.onDidChangeSelection(items => resolve(items[0])), - input.onDidHide(() => { - (async () => { - reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel); - })() - .catch(reject); - }) - ); - if (this.current) { - this.current.dispose(); - } - this.current = input; - this.current.show(); + this.steps.pop(); + step = this.steps.pop(); + } else if (err === InputFlowAction.resume) { + step = this.steps.pop(); + } else if (err === InputFlowAction.cancel) { + step = undefined; + } else { + throw err; + } + } + } + if (this.current) { + this.current.dispose(); + } + } + + async showQuickPick>({ title, step, totalSteps, items, activeItem, ignoreFocusOut, placeholder, buttons, shouldResume }: P) { + const disposables: Disposable[] = []; + try { + return await new Promise((resolve, reject) => { + const input = window.createQuickPick(); + input.title = title; + input.step = step; + input.totalSteps = totalSteps; + input.ignoreFocusOut = ignoreFocusOut ?? false; + input.placeholder = placeholder; + input.items = items; + input.buttons = [ + ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), + ...(buttons || []) + ]; + disposables.push( + input.onDidTriggerButton(item => { + if (item === QuickInputButtons.Back) { + reject(InputFlowAction.back); + } else { + resolve(item); + } + }), + input.onDidChangeSelection(items => resolve(items[0])), + input.onDidHide(() => { + (async () => { + reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel); + })() + .catch(reject); + }) + ); + if (this.current) { + this.current.dispose(); + } + this.current = input; + this.current.show(); if (activeItem) { - input.activeItems = [activeItem]; - } - }); - } finally { - disposables.forEach(d => d.dispose()); - } - } - - async showInputBox

({ title, step, totalSteps, value, prompt, validate, buttons, ignoreFocusOut, placeholder, shouldResume }: P) { - const disposables: Disposable[] = []; - try { - return await new Promise((resolve, reject) => { - const input = window.createInputBox(); - input.title = title; - input.step = step; - input.totalSteps = totalSteps; - input.value = value || ''; - input.prompt = prompt; - input.ignoreFocusOut = ignoreFocusOut ?? false; - input.placeholder = placeholder; - input.buttons = [ - ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), - ...(buttons || []) - ]; - let validating = validate(''); - disposables.push( - input.onDidTriggerButton(item => { - if (item === QuickInputButtons.Back) { - reject(InputFlowAction.back); - } else { - resolve(item); - } - }), - input.onDidAccept(async () => { - const value = input.value; - input.enabled = false; - input.busy = true; - if (!(await validate(value))) { - resolve(value); - } - input.enabled = true; - input.busy = false; - }), - input.onDidChangeValue(async text => { - const current = validate(text); - validating = current; - const validationMessage = await current; - if (current === validating) { - input.validationMessage = validationMessage; - } - }), - input.onDidHide(() => { - (async () => { - reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel); - })() - .catch(reject); - }) - ); - if (this.current) { - this.current.dispose(); - } - this.current = input; - this.current.show(); - }); - } finally { - disposables.forEach(d => d.dispose()); - } - } + input.activeItems = [activeItem]; + } + }); + } finally { + disposables.forEach(d => d.dispose()); + } + } + + async showInputBox

({ title, step, totalSteps, value, prompt, validate, buttons, ignoreFocusOut, placeholder, shouldResume }: P) { + const disposables: Disposable[] = []; + try { + return await new Promise((resolve, reject) => { + const input = window.createInputBox(); + input.title = title; + input.step = step; + input.totalSteps = totalSteps; + input.value = value || ''; + input.prompt = prompt; + input.ignoreFocusOut = ignoreFocusOut ?? false; + input.placeholder = placeholder; + input.buttons = [ + ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), + ...(buttons || []) + ]; + let validating = validate ? validate('') : Promise.resolve(undefined); + disposables.push( + input.onDidTriggerButton(item => { + if (item === QuickInputButtons.Back) { + reject(InputFlowAction.back); + } else { + resolve(item); + } + }), + input.onDidAccept(async () => { + const value = input.value; + input.enabled = false; + input.busy = true; + if (!(validate && await validate(value))) { + resolve(value); + } + input.enabled = true; + input.busy = false; + }), + input.onDidChangeValue(async text => { + if (validate) { + const current = validate(text); + validating = current; + const validationMessage = await current; + if (current === validating) { + input.validationMessage = validationMessage; + } + } + }), + input.onDidHide(() => { + (async () => { + reject(shouldResume && await shouldResume() ? InputFlowAction.resume : InputFlowAction.cancel); + })() + .catch(reject); + }) + ); + if (this.current) { + this.current.dispose(); + } + this.current = input; + this.current.show(); + }); + } finally { + disposables.forEach(d => d.dispose()); + } + } } \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/util.ts b/vscode/microsoft-kiota/src/util.ts new file mode 100644 index 0000000000..86c2a2e4ef --- /dev/null +++ b/vscode/microsoft-kiota/src/util.ts @@ -0,0 +1,95 @@ +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; +import { APIMANIFEST, CLIENT, CLIENTS, KIOTA_DIRECTORY, KIOTA_WORKSPACE_FILE, PLUGIN, PLUGINS } from './constants'; +import { migrateFromLockFile, displayMigrationMessages } from './migrateFromLockFile'; + +const clientTypes = [CLIENT, CLIENTS]; +const pluginTypes = [PLUGIN, PLUGINS, APIMANIFEST]; + +export function isClientType(type: string): boolean { + return clientTypes.includes(type); +} + +export function isPluginType(type: string): boolean { + return pluginTypes.includes(type); +} + +export async function updateTreeViewIcons(treeViewId: string, showIcons: boolean, showRegenerateIcon: boolean = false) { + await vscode.commands.executeCommand('setContext', `${treeViewId}.showIcons`, showIcons); + await vscode.commands.executeCommand('setContext', `${treeViewId}.showRegenerateIcon`, showRegenerateIcon); +} + +export function getWorkspaceJsonPath(): string { + return path.join(getWorkspaceJsonDirectory(),KIOTA_DIRECTORY, KIOTA_WORKSPACE_FILE); +}; + +export function getWorkspaceJsonDirectory(clientNameOrPluginName?: string): string { + const baseDir = path.join( + vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0 + ? vscode.workspace.workspaceFolders[0].uri.fsPath + : process.env.HOME ?? process.env.USERPROFILE ?? process.cwd() + ); + + let workspaceFolder = !vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0 + ? path.join(baseDir, 'kiota', clientNameOrPluginName ?? '') + : baseDir; + + if (!fs.existsSync(workspaceFolder)) { + fs.mkdirSync(workspaceFolder, { recursive: true }); + } + return workspaceFolder; +} + +//used to store output in the App Package directory in the case where the workspace is a Teams Toolkit Project +export function findAppPackageDirectory(directory: string): string | null { + if (!fs.existsSync(directory)) { + return null; + } + + const entries = fs.readdirSync(directory, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + + if (entry.isDirectory()) { + if (entry.name === 'appPackage') { + return fullPath; + } + + const subDirectory = findAppPackageDirectory(fullPath); + if (subDirectory) { + return subDirectory; + } + } + } + + return null; +} + +export async function handleMigration( + context: vscode.ExtensionContext, + workspaceFolder: vscode.WorkspaceFolder +): Promise { + vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: vscode.l10n.t("Migrating your API clients..."), + cancellable: false + }, async (progress) => { + progress.report({ increment: 0 }); + + try { + const migrationResult = await migrateFromLockFile(context, workspaceFolder.uri.fsPath); + + progress.report({ increment: 100 }); + + if (migrationResult && migrationResult.length > 0) { + displayMigrationMessages(migrationResult); + } else { + vscode.window.showWarningMessage(vscode.l10n.t("Migration completed, but no changes were detected.")); + } + } catch (error) { + vscode.window.showErrorMessage(vscode.l10n.t(`Migration failed: ${error}`)); + } + }); +} \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/workspaceTreeProvider.ts b/vscode/microsoft-kiota/src/workspaceTreeProvider.ts new file mode 100644 index 0000000000..e97a32d47b --- /dev/null +++ b/vscode/microsoft-kiota/src/workspaceTreeProvider.ts @@ -0,0 +1,71 @@ +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; +import { KIOTA_WORKSPACE_FILE } from './constants'; +import { getWorkspaceJsonPath } from './util'; + + +export class WorkspaceTreeProvider implements vscode.TreeDataProvider { + public isWSPresent: boolean; + private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); + readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; + constructor( isWSPresent: boolean) { + this.isWSPresent = isWSPresent; + } + + async refreshView(): Promise { + this._onDidChangeTreeData.fire(); +} + + async getChildren(element?: vscode.TreeItem): Promise { + if (!this.isWSPresent) { + return []; + } + if (!element) { + return [new vscode.TreeItem(KIOTA_WORKSPACE_FILE, vscode.TreeItemCollapsibleState.None)]; + } + return []; + } + + getTreeItem(element: vscode.TreeItem): vscode.TreeItem { + if (element) { + element.command = { + command: 'kiota.workspace.openWorkspaceFile', + title: vscode.l10n.t("Open File"), + arguments: [vscode.Uri.file(getWorkspaceJsonPath())] + }; + element.contextValue = 'file'; + } + return element; + } +} + +async function openResource(resource: vscode.Uri): Promise { + await vscode.window.showTextDocument(resource); +} +async function isKiotaWorkspaceFilePresent(): Promise { + if(!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0){ + return false; + } + const workspaceFileDir = path.resolve(getWorkspaceJsonPath()); + try { + await fs.promises.access(workspaceFileDir); + } catch (error) { + return false; + } + return true; +} + +export async function loadTreeView(context: vscode.ExtensionContext): Promise { + const treeDataProvider = new WorkspaceTreeProvider(await isKiotaWorkspaceFilePresent()); + context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(async () => { + treeDataProvider.isWSPresent = await isKiotaWorkspaceFilePresent(); + await vscode.commands.executeCommand('kiota.workspace.refresh'); // Refresh the tree view when workspace folders change + })); + context.subscriptions.push(vscode.window.createTreeView('kiota.workspace', { treeDataProvider })); + context.subscriptions.push(vscode.commands.registerCommand('kiota.workspace.openWorkspaceFile', openResource)); + context.subscriptions.push(vscode.commands.registerCommand('kiota.workspace.refresh', async () => { + treeDataProvider.isWSPresent = await isKiotaWorkspaceFilePresent(); + await treeDataProvider.refreshView(); + })); +}