mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 20:12:12 +00:00
Added the option to delete configuration plugins you placed yourself
This commit is contained in:
parent
0381cd9b2a
commit
6ae0b5280f
@ -3193,6 +3193,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T2809641588"] =
|
||||
-- You have selected {0} preview features.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T3513450626"] = "You have selected {0} preview features."
|
||||
|
||||
-- The '{0}' configuration plugin has been successfully removed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T2048783766"] = "The '{0}' configuration plugin has been successfully removed."
|
||||
|
||||
-- Delete Configuration Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T3395354991"] = "Delete Configuration Plugin"
|
||||
|
||||
-- The configuration plugin '{0}' could not be deleted: {1}
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T4140893414"] = "The configuration plugin '{0}' could not be deleted: {1}"
|
||||
|
||||
-- Delete configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T459830575"] = "Delete configuration plugin"
|
||||
|
||||
-- Preselected provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T1469984996"] = "Preselected provider"
|
||||
|
||||
@ -4750,6 +4762,84 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T823785464"] = "Allow th
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- {0} LLM providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T121235760"] = "{0} LLM providers"
|
||||
|
||||
-- {0} profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1238255445"] = "{0} profiles"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1642511898"] = "No"
|
||||
|
||||
-- {0} introductions on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2107991661"] = "{0} introductions on the welcome page"
|
||||
|
||||
-- {0} mandatory information
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2150386772"] = "{0} mandatory information"
|
||||
|
||||
-- You can install the plugin again later, but any changes you made to its settings are lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2156367745"] = "You can install the plugin again later, but any changes you made to its settings are lost."
|
||||
|
||||
-- {0} profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2342765572"] = "{0} profile"
|
||||
|
||||
-- {0} introduction on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2426110502"] = "{0} introduction on the welcome page"
|
||||
|
||||
-- {0} embedding providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2438407498"] = "{0} embedding providers"
|
||||
|
||||
-- Yes, delete it
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2466176832"] = "Yes, delete it"
|
||||
|
||||
-- This also removes everything the configuration plugin had set up:
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T264970454"] = "This also removes everything the configuration plugin had set up:"
|
||||
|
||||
-- {0} transcription provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2681055470"] = "{0} transcription provider"
|
||||
|
||||
-- {0} chat templates
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3235448458"] = "{0} chat templates"
|
||||
|
||||
-- {0} document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3278137746"] = "{0} document analysis policy"
|
||||
|
||||
-- The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T330559934"] = "The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well."
|
||||
|
||||
-- {0} LLM provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3410030691"] = "{0} LLM provider"
|
||||
|
||||
-- Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3616855807"] = "Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files."
|
||||
|
||||
-- {0} settings return to their default values
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3841220170"] = "{0} settings return to their default values"
|
||||
|
||||
-- {0} setting returns to its default value
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T384701293"] = "{0} setting returns to its default value"
|
||||
|
||||
-- {0} mandatory informations
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3971735909"] = "{0} mandatory informations"
|
||||
|
||||
-- {0} chat template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4147879421"] = "{0} chat template"
|
||||
|
||||
-- {0} data sources, including their credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4193757254"] = "{0} data sources, including their credentials in your operating system's keychain"
|
||||
|
||||
-- {0} document analysis policies
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T449490978"] = "{0} document analysis policies"
|
||||
|
||||
-- {0} data source, including its credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T511418335"] = "{0} data source, including its credentials in your operating system's keychain"
|
||||
|
||||
-- {0} transcription providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T767586087"] = "{0} transcription providers"
|
||||
|
||||
-- {0} embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T818101181"] = "{0} embedding provider"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T1642511898"] = "No"
|
||||
|
||||
@ -9649,6 +9739,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1138181282"]
|
||||
-- The assistant plugin directory is outside the local assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1211881977"] = "The assistant plugin directory is outside the local assistant plugin directory."
|
||||
|
||||
-- Only configuration plugins can be deleted this way.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1214012118"] = "Only configuration plugins can be deleted this way."
|
||||
|
||||
-- Only assistant plugins can be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1288328479"] = "Only assistant plugins can be edited."
|
||||
|
||||
@ -9661,6 +9754,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T139615196"] =
|
||||
-- Please select a plugin archive with the extension .mwplugin or .zip.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1809137998"] = "Please select a plugin archive with the extension .mwplugin or .zip."
|
||||
|
||||
-- Internal configuration plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1811106891"] = "Internal configuration plugins cannot be deleted."
|
||||
|
||||
-- The selected plugin archive does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1821013825"] = "The selected plugin archive does not exist."
|
||||
|
||||
@ -9682,6 +9778,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2441747251"]
|
||||
-- Config server managed assistant plugins cannot be replaced.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2594571117"] = "Config server managed assistant plugins cannot be replaced."
|
||||
|
||||
-- The configuration plugin directory is outside the plugins directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2613041269"] = "The configuration plugin directory is outside the plugins directory."
|
||||
|
||||
-- The assistant plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2682912892"] = "The assistant plugin has no local directory."
|
||||
|
||||
@ -9700,6 +9799,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2955055168"]
|
||||
-- The imported assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2971411166"] = "The imported assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- The configuration plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3073748821"] = "The configuration plugin directory does not exist."
|
||||
|
||||
-- Your organization has disabled importing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3212529834"] = "Your organization has disabled importing plugins."
|
||||
|
||||
@ -9730,6 +9832,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T584770023"] =
|
||||
-- The edited assistant plugin must keep the same plugin ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T693124809"] = "The edited assistant plugin must keep the same plugin ID."
|
||||
|
||||
-- The configuration plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T719938122"] = "The configuration plugin has no local directory."
|
||||
|
||||
-- Configuration plugins deployed by your organization cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T75764577"] = "Configuration plugins deployed by your organization cannot be deleted."
|
||||
|
||||
-- Internal assistant plugins cannot be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T816339833"] = "Internal assistant plugins cannot be edited."
|
||||
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
@inherits MSGComponentBase
|
||||
|
||||
@if (this.CanDelete)
|
||||
{
|
||||
<MudTooltip Text="@T("Delete configuration plugin")">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.DeleteOutline"
|
||||
Color="Color.Error"
|
||||
Variant="Variant.Text"
|
||||
Size="Size.Medium"
|
||||
Disabled="@this.isDeleting"
|
||||
OnClick="@this.DeleteConfigurationPluginAsync" />
|
||||
</MudTooltip>
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
using DialogOptions = AIStudio.Dialogs.DialogOptions;
|
||||
|
||||
namespace AIStudio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Lets users remove a configuration plugin they placed locally.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Configuration plugins have no activation switch, so without this action a local configuration
|
||||
/// could only be removed from the data directory by hand. Configurations deployed by an organization
|
||||
/// stay untouched: the action does not appear for them.
|
||||
/// </remarks>
|
||||
public partial class ConfigurationPluginDeleteAction : MSGComponentBase
|
||||
{
|
||||
[Parameter, EditorRequired]
|
||||
public IAvailablePlugin Plugin { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private PluginInstallService PluginInstallService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ILogger<ConfigurationPluginDeleteAction> Logger { get; init; } = null!;
|
||||
|
||||
private bool isDeleting;
|
||||
|
||||
private bool CanDelete => PluginInstallService.CanDeleteInstalledConfiguration(this.Plugin);
|
||||
|
||||
private async Task DeleteConfigurationPluginAsync()
|
||||
{
|
||||
if (!this.CanDelete || this.isDeleting)
|
||||
return;
|
||||
|
||||
// The deletion reaches beyond the plugin directory, so we show what it takes with it:
|
||||
var dialogParameters = new DialogParameters<ConfigurationPluginDeleteDialog>
|
||||
{
|
||||
{ x => x.PluginName, this.Plugin.Name },
|
||||
{ x => x.Summary, this.PluginInstallService.BuildConfigurationDeleteSummary(this.Plugin) },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ConfigurationPluginDeleteDialog>(this.T("Delete Configuration Plugin"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
this.isDeleting = true;
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await this.PluginInstallService.DeleteInstalledConfigurationAsync(this.Plugin, CancellationToken.None);
|
||||
if (!result.Success)
|
||||
{
|
||||
this.Logger.LogError("Failed to delete configuration plugin '{PluginName}' ({PluginId}) from '{PluginDirectory}' with issue '{Issue}'.", result.PluginName, result.PluginId, result.PluginDirectory, result.Issue);
|
||||
await this.MessageBus.SendError(new(Icons.Material.Filled.DeleteForever, string.Format(this.T("The configuration plugin '{0}' could not be deleted: {1}"), this.Plugin.Name, result.Issue)));
|
||||
return;
|
||||
}
|
||||
|
||||
await this.MessageBus.SendSuccess(new(Icons.Material.Filled.Check, string.Format(this.T("The '{0}' configuration plugin has been successfully removed."), result.PluginName)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isDeleting = false;
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
@inherits MSGComponentBase
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@(string.Format(T("Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files."), this.PluginName))
|
||||
</MudJustifiedText>
|
||||
|
||||
@if (this.Consequences.Count > 0)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-1">
|
||||
@T("This also removes everything the configuration plugin had set up:")
|
||||
</MudJustifiedText>
|
||||
|
||||
<MudList T="string" Class="mb-3">
|
||||
@foreach (var consequence in this.Consequences)
|
||||
{
|
||||
<MudListItem T="string" Icon="@Icons.Material.Filled.RemoveCircleOutline" IconColor="Color.Error">
|
||||
@consequence
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||
@T("The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well.")
|
||||
</MudJustifiedText>
|
||||
}
|
||||
|
||||
<MudJustifiedText Typo="Typo.body2">
|
||||
@T("You can install the plugin again later, but any changes you made to its settings are lost.")
|
||||
</MudJustifiedText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
|
||||
@T("No")
|
||||
</MudButton>
|
||||
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Error">
|
||||
@T("Yes, delete it")
|
||||
</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@ -0,0 +1,69 @@
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace AIStudio.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// Asks the user whether a local configuration plugin may be deleted, and shows what the deletion
|
||||
/// takes with it.
|
||||
/// </summary>
|
||||
public partial class ConfigurationPluginDeleteDialog : MSGComponentBase
|
||||
{
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the configuration plugin about to be deleted.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PluginName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// What the deletion removes besides the plugin directory.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ConfigurationPluginDeleteSummary Summary { get; set; } = ConfigurationPluginDeleteSummary.EMPTY;
|
||||
|
||||
private List<string> Consequences => this.BuildConsequences();
|
||||
|
||||
/// <summary>
|
||||
/// Turns the summary into the lines shown to the user. Only what is actually affected is listed,
|
||||
/// so the dialog stays short for a configuration plugin that just locks a single setting.
|
||||
/// </summary>
|
||||
private List<string> BuildConsequences()
|
||||
{
|
||||
var consequences = new List<string>();
|
||||
var summary = this.Summary;
|
||||
|
||||
Add(summary.LlmProviders, this.T("{0} LLM provider"), this.T("{0} LLM providers"));
|
||||
Add(summary.TranscriptionProviders, this.T("{0} transcription provider"), this.T("{0} transcription providers"));
|
||||
Add(summary.EmbeddingProviders, this.T("{0} embedding provider"), this.T("{0} embedding providers"));
|
||||
Add(summary.ChatTemplates, this.T("{0} chat template"), this.T("{0} chat templates"));
|
||||
Add(summary.Profiles, this.T("{0} profile"), this.T("{0} profiles"));
|
||||
Add(summary.DocumentAnalysisPolicies, this.T("{0} document analysis policy"), this.T("{0} document analysis policies"));
|
||||
Add(summary.MandatoryInfos, this.T("{0} mandatory information"), this.T("{0} mandatory informations"));
|
||||
Add(summary.Introductions, this.T("{0} introduction on the welcome page"), this.T("{0} introductions on the welcome page"));
|
||||
|
||||
// Data sources are called out separately: removing them also deletes their credentials from
|
||||
// the operating system's keychain, which the user cannot undo by reinstalling the plugin.
|
||||
Add(summary.DataSources,
|
||||
this.T("{0} data source, including its credentials in your operating system's keychain"),
|
||||
this.T("{0} data sources, including their credentials in your operating system's keychain"));
|
||||
|
||||
Add(summary.LockedSettings, this.T("{0} setting returns to its default value"), this.T("{0} settings return to their default values"));
|
||||
|
||||
return consequences;
|
||||
|
||||
void Add(int count, string singular, string plural)
|
||||
{
|
||||
if (count > 0)
|
||||
consequences.Add(string.Format(count == 1 ? singular : plural, count));
|
||||
}
|
||||
}
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
|
||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
@ -139,6 +139,7 @@
|
||||
@if (context is IAvailablePlugin availablePlugin)
|
||||
{
|
||||
<AssistantPluginDeleteAction Plugin="@availablePlugin" />
|
||||
<ConfigurationPluginDeleteAction Plugin="@availablePlugin" />
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
@ -3195,6 +3195,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T2809641588"] =
|
||||
-- You have selected {0} preview features.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T3513450626"] = "Sie haben {0} Vorschaufunktionen ausgewählt."
|
||||
|
||||
-- The '{0}' configuration plugin has been successfully removed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T2048783766"] = "Das Konfigurations-Plugin „{0}“ wurde erfolgreich entfernt."
|
||||
|
||||
-- Delete Configuration Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T3395354991"] = "Konfigurations-Plugin löschen"
|
||||
|
||||
-- The configuration plugin '{0}' could not be deleted: {1}
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T4140893414"] = "Das Konfigurations-Plugin „{0}“ konnte nicht gelöscht werden: {1}"
|
||||
|
||||
-- Delete configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T459830575"] = "Konfigurations-Plugin löschen"
|
||||
|
||||
-- Preselected provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T1469984996"] = "Vorausgewählter Anbieter"
|
||||
|
||||
@ -4752,6 +4764,84 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T823785464"] = "Erlauben
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T900713019"] = "Abbrechen"
|
||||
|
||||
-- {0} LLM providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T121235760"] = "{0} LLM-Anbieter"
|
||||
|
||||
-- {0} profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1238255445"] = "{0} Profile"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1642511898"] = "Nein"
|
||||
|
||||
-- {0} introductions on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2107991661"] = "{0} Einführungen auf der Willkommensseite"
|
||||
|
||||
-- {0} mandatory information
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2150386772"] = "{0} Pflichtangabe"
|
||||
|
||||
-- You can install the plugin again later, but any changes you made to its settings are lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2156367745"] = "Du kannst das Plugin später erneut installieren, aber alle Änderungen an seinen Einstellungen gehen verloren."
|
||||
|
||||
-- {0} profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2342765572"] = "{0} Profil"
|
||||
|
||||
-- {0} introduction on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2426110502"] = "{0} Einführung auf der Willkommensseite"
|
||||
|
||||
-- {0} embedding providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2438407498"] = "{0} Anbieter für Einbettungen"
|
||||
|
||||
-- Yes, delete it
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2466176832"] = "Ja, löschen"
|
||||
|
||||
-- This also removes everything the configuration plugin had set up:
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T264970454"] = "Dadurch wird auch alles entfernt, was das Konfigurations-Plugin eingerichtet hat:"
|
||||
|
||||
-- {0} transcription provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2681055470"] = "{0} Anbieter für Transkriptionen"
|
||||
|
||||
-- {0} chat templates
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3235448458"] = "{0} Chat-Vorlagen"
|
||||
|
||||
-- {0} document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3278137746"] = "{0} Regelwerk der Dokumentenanalyse"
|
||||
|
||||
-- The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T330559934"] = "Das Konfigurations-Plugin wird nicht ausgeführt, daher können wir nicht feststellen, was es eingerichtet hat. Alles, was es konfiguriert hat, wird ebenfalls entfernt."
|
||||
|
||||
-- {0} LLM provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3410030691"] = "{0} LLM-Anbieter"
|
||||
|
||||
-- Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3616855807"] = "Möchten Sie das Konfigurations-Plugin „{0}“ wirklich löschen? Dadurch werden seine lokalen Plugin-Dateien dauerhaft gelöscht."
|
||||
|
||||
-- {0} settings return to their default values
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3841220170"] = "{0} Einstellungen werden auf ihre Standardwerte zurückgesetzt."
|
||||
|
||||
-- {0} setting returns to its default value
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T384701293"] = "{0} Einstellung wird auf den Standardwert zurückgesetzt."
|
||||
|
||||
-- {0} mandatory informations
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3971735909"] = "{0} Pflichtangaben"
|
||||
|
||||
-- {0} chat template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4147879421"] = "{0} Chat-Vorlage"
|
||||
|
||||
-- {0} data sources, including their credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4193757254"] = "{0} Datenquellen, einschließlich ihrer Zugangsdaten im Schlüsselbund Ihres Betriebssystems"
|
||||
|
||||
-- {0} document analysis policies
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T449490978"] = "{0} Regelwerke der Dokumentenanalyse"
|
||||
|
||||
-- {0} data source, including its credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T511418335"] = "{0} Datenquelle einschließlich ihrer Zugangsdaten im Schlüsselbund Ihres Betriebssystems"
|
||||
|
||||
-- {0} transcription providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T767586087"] = "{0} Anbieter für Transkriptionen"
|
||||
|
||||
-- {0} embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T818101181"] = "{0} Anbieter für Einbettungen"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T1642511898"] = "Nein"
|
||||
|
||||
@ -9591,102 +9681,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::ASSISTANTPLUGINGENERATIONSERVICE::T4
|
||||
-- Please create an assistant draft first.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::ASSISTANTPLUGINGENERATIONSERVICE::T4269176489"] = "Bitte erstellen Sie zuerst einen Entwurf für den Assistenten."
|
||||
|
||||
-- Internal assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1084244321"] = "Interne Assistenten-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1138181282"] = "Dieses Plugin-Archiv gibt an, von einem Konfigurationsserver verwaltet zu werden. Nur die IT-Abteilung Ihrer Organisation kann solche Plugins bereitstellen."
|
||||
|
||||
-- The assistant plugin directory is outside the local assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1211881977"] = "Das Assistenten-Plugin-Verzeichnis befindet sich außerhalb des lokalen Assistenten-Plugin-Verzeichnisses."
|
||||
|
||||
-- Only assistant plugins can be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1288328479"] = "Nur Assistant-Plugins können bearbeitet werden."
|
||||
|
||||
-- The assistant cannot be deleted while background work is still running.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1318944584"] = "Der Assistent kann nicht gelöscht werden, solange noch Hintergrundaktivitäten ausgeführt werden."
|
||||
|
||||
-- Currently, only assistant plugins can be imported.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T139615196"] = "Derzeit können nur Assistenten-Plugins importiert werden."
|
||||
|
||||
-- Please select a plugin archive with the extension .mwplugin or .zip.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1809137998"] = "Bitte wählen Sie ein Plugin-Archiv mit der Dateiendung .mwplugin oder .zip aus."
|
||||
|
||||
-- The selected plugin archive does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1821013825"] = "Das ausgewählte Plugin-Archiv existiert nicht."
|
||||
|
||||
-- No Lua plugin code was generated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1839013358"] = "Es wurde kein Lua-Plugin-Code generiert."
|
||||
|
||||
-- The assistant plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2148384567"] = "Das Verzeichnis für das Assistenten-Plugin existiert nicht."
|
||||
|
||||
-- The resolved plugin directory is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2223071618"] = "Das ermittelte Plugin-Verzeichnis liegt außerhalb des Plugin-Verzeichnisses des Assistenten."
|
||||
|
||||
-- Unexpected error: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2350673880"] = "Unerwarteter Fehler: {0}"
|
||||
|
||||
-- The generated assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2441747251"] = "Das generierte Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- Config server managed assistant plugins cannot be replaced.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2594571117"] = "Vom Konfigurationsserver verwaltete Assistenten-Plugins können nicht ersetzt werden."
|
||||
|
||||
-- The assistant plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2682912892"] = "Das Assistenten-Plugin hat kein lokales Verzeichnis."
|
||||
|
||||
-- The AI Studio data directory is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2712481762"] = "Das Datenverzeichnis von AI Studio ist noch nicht initialisiert."
|
||||
|
||||
-- The imported assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2777304537"] = "Das importierte Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- Only assistant plugins can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2864597027"] = "Nur Assistant-Plugins können gelöscht werden."
|
||||
|
||||
-- The generated plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2955055168"] = "Das generierte Plugin ist kein Assistenten-Plugin. Problem: {0}"
|
||||
|
||||
-- The imported assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2971411166"] = "Das importierte Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- Your organization has disabled importing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3212529834"] = "Ihre Organisation hat das Importieren von Plugins deaktiviert."
|
||||
|
||||
-- The plugin archive must contain exactly one plugin.lua file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3355918609"] = "Das Plugin-Archiv muss genau eine plugin.lua-Datei enthalten."
|
||||
|
||||
-- Config Server managed assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3751820312"] = "Von einem Config-Server verwaltete Assistenten-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- Only assistants generated by the Assistant Builder can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3940247198"] = "Nur mit dem Assistant Builder erstellte Assistenten können gelöscht werden."
|
||||
|
||||
-- The edited plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984111892"] = "Das bearbeitete Plugin ist kein Assistenten-Plugin. Problem: {0}"
|
||||
|
||||
-- The plugin system is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984839613"] = "Das Plugin-System ist noch nicht initialisiert."
|
||||
|
||||
-- The plugin file is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T4062980447"] = "Die Plugin-Datei befindet sich außerhalb des Assistenten-Plugin-Verzeichnisses."
|
||||
|
||||
-- The edited assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T554567780"] = "Das bearbeitete Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- The edited assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T584770023"] = "Das bearbeitete Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- The edited assistant plugin must keep the same plugin ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T693124809"] = "Das bearbeitete Assistant-Plugin muss dieselbe Plugin-ID beibehalten."
|
||||
|
||||
-- Internal assistant plugins cannot be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T816339833"] = "Interne Assistenten-Plugins können nicht bearbeitet werden."
|
||||
|
||||
-- The generated assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T939708112"] = "Das generierte Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- The voice recording shortcut currently works only while AI Studio is focused.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T1204510649"] = "Die Tastenkombination für Sprachaufnahmen funktioniert derzeit nur, wenn AI Studio im Vordergrund aktiv ist."
|
||||
|
||||
@ -9738,6 +9732,120 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T18544701
|
||||
-- Pandoc may be required for importing files.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T2596465560"] = "Zum Importieren von Dateien kann Pandoc erforderlich sein."
|
||||
|
||||
-- Internal assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1084244321"] = "Interne Assistenten-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1138181282"] = "Dieses Plugin-Archiv gibt an, von einem Konfigurationsserver verwaltet zu werden. Nur die IT-Abteilung Ihrer Organisation kann solche Plugins bereitstellen."
|
||||
|
||||
-- The assistant plugin directory is outside the local assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1211881977"] = "Das Assistenten-Plugin-Verzeichnis befindet sich außerhalb des lokalen Assistenten-Plugin-Verzeichnisses."
|
||||
|
||||
-- Only configuration plugins can be deleted this way.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1214012118"] = "Nur Konfigurations-Plugins können auf diese Weise gelöscht werden."
|
||||
|
||||
-- Only assistant plugins can be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1288328479"] = "Nur Assistant-Plugins können bearbeitet werden."
|
||||
|
||||
-- The assistant cannot be deleted while background work is still running.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1318944584"] = "Der Assistent kann nicht gelöscht werden, solange noch Hintergrundaktivitäten ausgeführt werden."
|
||||
|
||||
-- Currently, only assistant plugins can be imported.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T139615196"] = "Derzeit können nur Assistenten-Plugins importiert werden."
|
||||
|
||||
-- Please select a plugin archive with the extension .mwplugin or .zip.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1809137998"] = "Bitte wählen Sie ein Plugin-Archiv mit der Dateiendung .mwplugin oder .zip aus."
|
||||
|
||||
-- Internal configuration plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1811106891"] = "Interne Konfigurations-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- The selected plugin archive does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1821013825"] = "Das ausgewählte Plugin-Archiv existiert nicht."
|
||||
|
||||
-- No Lua plugin code was generated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1839013358"] = "Es wurde kein Lua-Plugin-Code generiert."
|
||||
|
||||
-- The assistant plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2148384567"] = "Das Verzeichnis für das Assistenten-Plugin existiert nicht."
|
||||
|
||||
-- The resolved plugin directory is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2223071618"] = "Das ermittelte Plugin-Verzeichnis liegt außerhalb des Plugin-Verzeichnisses des Assistenten."
|
||||
|
||||
-- Unexpected error: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2350673880"] = "Unerwarteter Fehler: {0}"
|
||||
|
||||
-- The generated assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2441747251"] = "Das generierte Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- Config server managed assistant plugins cannot be replaced.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2594571117"] = "Vom Konfigurationsserver verwaltete Assistenten-Plugins können nicht ersetzt werden."
|
||||
|
||||
-- The configuration plugin directory is outside the plugins directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2613041269"] = "Das Konfigurations-Plugin-Verzeichnis befindet sich außerhalb des Plugin-Verzeichnisses."
|
||||
|
||||
-- The assistant plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2682912892"] = "Das Assistenten-Plugin hat kein lokales Verzeichnis."
|
||||
|
||||
-- The AI Studio data directory is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2712481762"] = "Das Datenverzeichnis von AI Studio ist noch nicht initialisiert."
|
||||
|
||||
-- The imported assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2777304537"] = "Das importierte Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- Only assistant plugins can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2864597027"] = "Nur Assistant-Plugins können gelöscht werden."
|
||||
|
||||
-- The generated plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2955055168"] = "Das generierte Plugin ist kein Assistenten-Plugin. Problem: {0}"
|
||||
|
||||
-- The imported assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2971411166"] = "Das importierte Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- The configuration plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3073748821"] = "Das Konfigurations-Plugin-Verzeichnis existiert nicht."
|
||||
|
||||
-- Your organization has disabled importing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3212529834"] = "Ihre Organisation hat das Importieren von Plugins deaktiviert."
|
||||
|
||||
-- The plugin archive must contain exactly one plugin.lua file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3355918609"] = "Das Plugin-Archiv muss genau eine plugin.lua-Datei enthalten."
|
||||
|
||||
-- Config Server managed assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3751820312"] = "Von einem Config-Server verwaltete Assistenten-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- Only assistants generated by the Assistant Builder can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3940247198"] = "Nur mit dem Assistant Builder erstellte Assistenten können gelöscht werden."
|
||||
|
||||
-- The edited plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984111892"] = "Das bearbeitete Plugin ist kein Assistenten-Plugin. Problem: {0}"
|
||||
|
||||
-- The plugin system is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984839613"] = "Das Plugin-System ist noch nicht initialisiert."
|
||||
|
||||
-- The plugin file is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T4062980447"] = "Die Plugin-Datei befindet sich außerhalb des Assistenten-Plugin-Verzeichnisses."
|
||||
|
||||
-- The edited assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T554567780"] = "Das bearbeitete Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- The edited assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T584770023"] = "Das bearbeitete Assistenten-Plugin verwendet die ID eines anderen installierten Plugins."
|
||||
|
||||
-- The edited assistant plugin must keep the same plugin ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T693124809"] = "Das bearbeitete Assistant-Plugin muss dieselbe Plugin-ID beibehalten."
|
||||
|
||||
-- The configuration plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T719938122"] = "Das Konfigurations-Plugin hat kein lokales Verzeichnis."
|
||||
|
||||
-- Configuration plugins deployed by your organization cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T75764577"] = "Von Ihrer Organisation bereitgestellte Konfigurations-Plugins können nicht gelöscht werden."
|
||||
|
||||
-- Internal assistant plugins cannot be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T816339833"] = "Interne Assistenten-Plugins können nicht bearbeitet werden."
|
||||
|
||||
-- The generated assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T939708112"] = "Das generierte Assistenten-Plugin ist ungültig. Problem: {0}"
|
||||
|
||||
-- Internal plugins cannot be shared.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGINSHARESERVICE::T1668534561"] = "Interne Plugins können nicht geteilt werden."
|
||||
|
||||
|
||||
@ -3195,6 +3195,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T2809641588"] =
|
||||
-- You have selected {0} preview features.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T3513450626"] = "You have selected {0} preview features."
|
||||
|
||||
-- The '{0}' configuration plugin has been successfully removed.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T2048783766"] = "The '{0}' configuration plugin has been successfully removed."
|
||||
|
||||
-- Delete Configuration Plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T3395354991"] = "Delete Configuration Plugin"
|
||||
|
||||
-- The configuration plugin '{0}' could not be deleted: {1}
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T4140893414"] = "The configuration plugin '{0}' could not be deleted: {1}"
|
||||
|
||||
-- Delete configuration plugin
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPLUGINDELETEACTION::T459830575"] = "Delete configuration plugin"
|
||||
|
||||
-- Preselected provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T1469984996"] = "Preselected provider"
|
||||
|
||||
@ -4752,6 +4764,84 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T823785464"] = "Allow th
|
||||
-- Cancel
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T900713019"] = "Cancel"
|
||||
|
||||
-- {0} LLM providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T121235760"] = "{0} LLM providers"
|
||||
|
||||
-- {0} profiles
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1238255445"] = "{0} profiles"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T1642511898"] = "No"
|
||||
|
||||
-- {0} introductions on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2107991661"] = "{0} introductions on the welcome page"
|
||||
|
||||
-- {0} mandatory information
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2150386772"] = "{0} mandatory information"
|
||||
|
||||
-- You can install the plugin again later, but any changes you made to its settings are lost.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2156367745"] = "You can install the plugin again later, but any changes you made to its settings are lost."
|
||||
|
||||
-- {0} profile
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2342765572"] = "{0} profile"
|
||||
|
||||
-- {0} introduction on the welcome page
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2426110502"] = "{0} introduction on the welcome page"
|
||||
|
||||
-- {0} embedding providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2438407498"] = "{0} embedding providers"
|
||||
|
||||
-- Yes, delete it
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2466176832"] = "Yes, delete it"
|
||||
|
||||
-- This also removes everything the configuration plugin had set up:
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T264970454"] = "This also removes everything the configuration plugin had set up:"
|
||||
|
||||
-- {0} transcription provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T2681055470"] = "{0} transcription provider"
|
||||
|
||||
-- {0} chat templates
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3235448458"] = "{0} chat templates"
|
||||
|
||||
-- {0} document analysis policy
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3278137746"] = "{0} document analysis policy"
|
||||
|
||||
-- The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T330559934"] = "The configuration plugin is not running, so we cannot tell what it had set up. Anything it configured will be removed as well."
|
||||
|
||||
-- {0} LLM provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3410030691"] = "{0} LLM provider"
|
||||
|
||||
-- Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3616855807"] = "Do you really want to delete the configuration plugin '{0}'? This permanently deletes its local plugin files."
|
||||
|
||||
-- {0} settings return to their default values
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3841220170"] = "{0} settings return to their default values"
|
||||
|
||||
-- {0} setting returns to its default value
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T384701293"] = "{0} setting returns to its default value"
|
||||
|
||||
-- {0} mandatory informations
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T3971735909"] = "{0} mandatory informations"
|
||||
|
||||
-- {0} chat template
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4147879421"] = "{0} chat template"
|
||||
|
||||
-- {0} data sources, including their credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T4193757254"] = "{0} data sources, including their credentials in your operating system's keychain"
|
||||
|
||||
-- {0} document analysis policies
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T449490978"] = "{0} document analysis policies"
|
||||
|
||||
-- {0} data source, including its credentials in your operating system's keychain
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T511418335"] = "{0} data source, including its credentials in your operating system's keychain"
|
||||
|
||||
-- {0} transcription providers
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T767586087"] = "{0} transcription providers"
|
||||
|
||||
-- {0} embedding provider
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIGURATIONPLUGINDELETEDIALOG::T818101181"] = "{0} embedding provider"
|
||||
|
||||
-- No
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CONFIRMDIALOG::T1642511898"] = "No"
|
||||
|
||||
@ -9591,102 +9681,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::ASSISTANTPLUGINGENERATIONSERVICE::T4
|
||||
-- Please create an assistant draft first.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::ASSISTANTPLUGINGENERATIONSERVICE::T4269176489"] = "Please create an assistant draft first."
|
||||
|
||||
-- Internal assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1084244321"] = "Internal assistant plugins cannot be deleted."
|
||||
|
||||
-- This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1138181282"] = "This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins."
|
||||
|
||||
-- The assistant plugin directory is outside the local assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1211881977"] = "The assistant plugin directory is outside the local assistant plugin directory."
|
||||
|
||||
-- Only assistant plugins can be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1288328479"] = "Only assistant plugins can be edited."
|
||||
|
||||
-- The assistant cannot be deleted while background work is still running.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1318944584"] = "The assistant cannot be deleted while background work is still running."
|
||||
|
||||
-- Currently, only assistant plugins can be imported.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T139615196"] = "Currently, only assistant plugins can be imported."
|
||||
|
||||
-- Please select a plugin archive with the extension .mwplugin or .zip.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1809137998"] = "Please select a plugin archive with the extension .mwplugin or .zip."
|
||||
|
||||
-- The selected plugin archive does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1821013825"] = "The selected plugin archive does not exist."
|
||||
|
||||
-- No Lua plugin code was generated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1839013358"] = "No Lua plugin code was generated."
|
||||
|
||||
-- The assistant plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2148384567"] = "The assistant plugin directory does not exist."
|
||||
|
||||
-- The resolved plugin directory is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2223071618"] = "The resolved plugin directory is outside the assistant plugin directory."
|
||||
|
||||
-- Unexpected error: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2350673880"] = "Unexpected error: {0}"
|
||||
|
||||
-- The generated assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2441747251"] = "The generated assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- Config server managed assistant plugins cannot be replaced.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2594571117"] = "Config server managed assistant plugins cannot be replaced."
|
||||
|
||||
-- The assistant plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2682912892"] = "The assistant plugin has no local directory."
|
||||
|
||||
-- The AI Studio data directory is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2712481762"] = "The AI Studio data directory is not initialized yet."
|
||||
|
||||
-- The imported assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2777304537"] = "The imported assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- Only assistant plugins can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2864597027"] = "Only assistant plugins can be deleted."
|
||||
|
||||
-- The generated plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2955055168"] = "The generated plugin is not an assistant plugin. Issue: {0}"
|
||||
|
||||
-- The imported assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2971411166"] = "The imported assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- Your organization has disabled importing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3212529834"] = "Your organization has disabled importing plugins."
|
||||
|
||||
-- The plugin archive must contain exactly one plugin.lua file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3355918609"] = "The plugin archive must contain exactly one plugin.lua file."
|
||||
|
||||
-- Config Server managed assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3751820312"] = "Config Server managed assistant plugins cannot be deleted."
|
||||
|
||||
-- Only assistants generated by the Assistant Builder can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3940247198"] = "Only assistants generated by the Assistant Builder can be deleted."
|
||||
|
||||
-- The edited plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984111892"] = "The edited plugin is not an assistant plugin. Issue: {0}"
|
||||
|
||||
-- The plugin system is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984839613"] = "The plugin system is not initialized yet."
|
||||
|
||||
-- The plugin file is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T4062980447"] = "The plugin file is outside the assistant plugin directory."
|
||||
|
||||
-- The edited assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T554567780"] = "The edited assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- The edited assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T584770023"] = "The edited assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- The edited assistant plugin must keep the same plugin ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T693124809"] = "The edited assistant plugin must keep the same plugin ID."
|
||||
|
||||
-- Internal assistant plugins cannot be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T816339833"] = "Internal assistant plugins cannot be edited."
|
||||
|
||||
-- The generated assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T939708112"] = "The generated assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- The voice recording shortcut currently works only while AI Studio is focused.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::GLOBALSHORTCUTSERVICE::T1204510649"] = "The voice recording shortcut currently works only while AI Studio is focused."
|
||||
|
||||
@ -9738,6 +9732,120 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T18544701
|
||||
-- Pandoc may be required for importing files.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PANDOCAVAILABILITYSERVICE::T2596465560"] = "Pandoc may be required for importing files."
|
||||
|
||||
-- Internal assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1084244321"] = "Internal assistant plugins cannot be deleted."
|
||||
|
||||
-- This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1138181282"] = "This plugin archive declares itself as managed by a config server. Only the IT department of your organization might deploy such plugins."
|
||||
|
||||
-- The assistant plugin directory is outside the local assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1211881977"] = "The assistant plugin directory is outside the local assistant plugin directory."
|
||||
|
||||
-- Only configuration plugins can be deleted this way.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1214012118"] = "Only configuration plugins can be deleted this way."
|
||||
|
||||
-- Only assistant plugins can be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1288328479"] = "Only assistant plugins can be edited."
|
||||
|
||||
-- The assistant cannot be deleted while background work is still running.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1318944584"] = "The assistant cannot be deleted while background work is still running."
|
||||
|
||||
-- Currently, only assistant plugins can be imported.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T139615196"] = "Currently, only assistant plugins can be imported."
|
||||
|
||||
-- Please select a plugin archive with the extension .mwplugin or .zip.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1809137998"] = "Please select a plugin archive with the extension .mwplugin or .zip."
|
||||
|
||||
-- Internal configuration plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1811106891"] = "Internal configuration plugins cannot be deleted."
|
||||
|
||||
-- The selected plugin archive does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1821013825"] = "The selected plugin archive does not exist."
|
||||
|
||||
-- No Lua plugin code was generated.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T1839013358"] = "No Lua plugin code was generated."
|
||||
|
||||
-- The assistant plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2148384567"] = "The assistant plugin directory does not exist."
|
||||
|
||||
-- The resolved plugin directory is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2223071618"] = "The resolved plugin directory is outside the assistant plugin directory."
|
||||
|
||||
-- Unexpected error: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2350673880"] = "Unexpected error: {0}"
|
||||
|
||||
-- The generated assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2441747251"] = "The generated assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- Config server managed assistant plugins cannot be replaced.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2594571117"] = "Config server managed assistant plugins cannot be replaced."
|
||||
|
||||
-- The configuration plugin directory is outside the plugins directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2613041269"] = "The configuration plugin directory is outside the plugins directory."
|
||||
|
||||
-- The assistant plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2682912892"] = "The assistant plugin has no local directory."
|
||||
|
||||
-- The AI Studio data directory is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2712481762"] = "The AI Studio data directory is not initialized yet."
|
||||
|
||||
-- The imported assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2777304537"] = "The imported assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- Only assistant plugins can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2864597027"] = "Only assistant plugins can be deleted."
|
||||
|
||||
-- The generated plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2955055168"] = "The generated plugin is not an assistant plugin. Issue: {0}"
|
||||
|
||||
-- The imported assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T2971411166"] = "The imported assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- The configuration plugin directory does not exist.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3073748821"] = "The configuration plugin directory does not exist."
|
||||
|
||||
-- Your organization has disabled importing plugins.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3212529834"] = "Your organization has disabled importing plugins."
|
||||
|
||||
-- The plugin archive must contain exactly one plugin.lua file.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3355918609"] = "The plugin archive must contain exactly one plugin.lua file."
|
||||
|
||||
-- Config Server managed assistant plugins cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3751820312"] = "Config Server managed assistant plugins cannot be deleted."
|
||||
|
||||
-- Only assistants generated by the Assistant Builder can be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3940247198"] = "Only assistants generated by the Assistant Builder can be deleted."
|
||||
|
||||
-- The edited plugin is not an assistant plugin. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984111892"] = "The edited plugin is not an assistant plugin. Issue: {0}"
|
||||
|
||||
-- The plugin system is not initialized yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T3984839613"] = "The plugin system is not initialized yet."
|
||||
|
||||
-- The plugin file is outside the assistant plugin directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T4062980447"] = "The plugin file is outside the assistant plugin directory."
|
||||
|
||||
-- The edited assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T554567780"] = "The edited assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- The edited assistant plugin uses the ID of another installed plugin.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T584770023"] = "The edited assistant plugin uses the ID of another installed plugin."
|
||||
|
||||
-- The edited assistant plugin must keep the same plugin ID.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T693124809"] = "The edited assistant plugin must keep the same plugin ID."
|
||||
|
||||
-- The configuration plugin has no local directory.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T719938122"] = "The configuration plugin has no local directory."
|
||||
|
||||
-- Configuration plugins deployed by your organization cannot be deleted.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T75764577"] = "Configuration plugins deployed by your organization cannot be deleted."
|
||||
|
||||
-- Internal assistant plugins cannot be edited.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T816339833"] = "Internal assistant plugins cannot be edited."
|
||||
|
||||
-- The generated assistant plugin is invalid. Issue: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGININSTALLSERVICE::T939708112"] = "The generated assistant plugin is invalid. Issue: {0}"
|
||||
|
||||
-- Internal plugins cannot be shared.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::PLUGINSHARESERVICE::T1668534561"] = "Internal plugins cannot be shared."
|
||||
|
||||
|
||||
@ -96,20 +96,33 @@ public static partial class PluginFactory
|
||||
/// </remarks>
|
||||
/// <param name="pluginPath">The directory of the plugin.</param>
|
||||
/// <returns>True when the directory is nested in the enterprise configuration directory.</returns>
|
||||
public static bool IsEnterpriseConfigurationPath(string? pluginPath)
|
||||
public static bool IsEnterpriseConfigurationPath(string? pluginPath) => IsPathInside(ENTERPRISE_CONFIGURATION_PLUGINS_ROOT, pluginPath);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a plugin directory is stored below the plugins directory of AI Studio.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Everything that removes or replaces plugin files checks this first, so a plugin directory
|
||||
/// which points somewhere else can never be touched.
|
||||
/// </remarks>
|
||||
/// <param name="pluginPath">The directory of the plugin.</param>
|
||||
/// <returns>True when the directory is nested in the plugins directory.</returns>
|
||||
public static bool IsInsidePluginsRoot(string? pluginPath) => IsPathInside(PLUGINS_ROOT, pluginPath);
|
||||
|
||||
private static bool IsPathInside(string rootDirectory, string? pluginPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pluginPath) || string.IsNullOrWhiteSpace(ENTERPRISE_CONFIGURATION_PLUGINS_ROOT))
|
||||
if (string.IsNullOrWhiteSpace(pluginPath) || string.IsNullOrWhiteSpace(rootDirectory))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var configurationRoot = Path.GetFullPath(ENTERPRISE_CONFIGURATION_PLUGINS_ROOT).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
var root = Path.GetFullPath(rootDirectory).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
var pluginDirectory = Path.GetFullPath(pluginPath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
return pluginDirectory.StartsWith(configurationRoot, StringComparison.OrdinalIgnoreCase);
|
||||
return pluginDirectory.StartsWith(root, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.LogWarning(e, $"Was not able to check whether the plugin directory '{pluginPath}' belongs to the enterprise configuration directory. Treating it as a local plugin.");
|
||||
LOG.LogWarning(e, $"Was not able to check whether the plugin directory '{pluginPath}' is nested in '{rootDirectory}'. Treating it as unrelated.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed record AssistantPluginDeleteResult(bool Success, Guid PluginId, string PluginName, string PluginDirectory, string Issue);
|
||||
@ -0,0 +1,42 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
/// <summary>
|
||||
/// What deleting a local configuration plugin takes with it, besides the plugin directory itself.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A configuration plugin owns everything it configured. Removing it therefore removes its providers,
|
||||
/// data sources, chat templates, and profiles, and it resets the settings it had locked. Users cannot
|
||||
/// see any of that on the plugins page, so we show it before they confirm the deletion.
|
||||
/// </remarks>
|
||||
public sealed record ConfigurationPluginDeleteSummary(
|
||||
int LlmProviders,
|
||||
int TranscriptionProviders,
|
||||
int EmbeddingProviders,
|
||||
int DataSources,
|
||||
int ChatTemplates,
|
||||
int Profiles,
|
||||
int DocumentAnalysisPolicies,
|
||||
int LockedSettings,
|
||||
int MandatoryInfos,
|
||||
int Introductions)
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty summary, used when the configuration plugin is not running and we cannot tell what it configured.
|
||||
/// </summary>
|
||||
public static readonly ConfigurationPluginDeleteSummary EMPTY = new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// True when the deletion affects anything beyond the plugin directory.
|
||||
/// </summary>
|
||||
public bool HasAnyConsequence =>
|
||||
this.LlmProviders > 0 ||
|
||||
this.TranscriptionProviders > 0 ||
|
||||
this.EmbeddingProviders > 0 ||
|
||||
this.DataSources > 0 ||
|
||||
this.ChatTemplates > 0 ||
|
||||
this.Profiles > 0 ||
|
||||
this.DocumentAnalysisPolicies > 0 ||
|
||||
this.LockedSettings > 0 ||
|
||||
this.MandatoryInfos > 0 ||
|
||||
this.Introductions > 0;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Tools.Services;
|
||||
|
||||
public sealed record PluginDeleteResult(bool Success, Guid PluginId, string PluginName, string PluginDirectory, string Issue);
|
||||
@ -30,7 +30,7 @@ public sealed class PluginInstallService
|
||||
|
||||
private static AssistantPluginCheckResult CheckError(string issue) => new(false, Guid.Empty, string.Empty, issue);
|
||||
|
||||
private static AssistantPluginDeleteResult DeleteError(IPluginMetadata plugin, string pluginDirectory, string issue) => new(false, plugin.Id, plugin.Name, pluginDirectory, issue);
|
||||
private static PluginDeleteResult DeleteError(IPluginMetadata plugin, string pluginDirectory, string issue) => new(false, plugin.Id, plugin.Name, pluginDirectory, issue);
|
||||
|
||||
private static AssistantPluginUpdateResult UpdateError(IPluginMetadata plugin, string pluginDirectory, string issue) => new(false, plugin.Id, plugin.Name, pluginDirectory, issue);
|
||||
|
||||
@ -48,6 +48,49 @@ public sealed class PluginInstallService
|
||||
/// </summary>
|
||||
public static bool CanDeleteInstalledAssistant(IAvailablePlugin plugin) => string.IsNullOrWhiteSpace(GetAssistantDeletionEligibilityIssue(plugin));
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a plugin is a local configuration plugin that users may delete.
|
||||
/// </summary>
|
||||
public static bool CanDeleteInstalledConfiguration(IAvailablePlugin plugin) => string.IsNullOrWhiteSpace(GetConfigurationDeletionEligibilityIssue(plugin));
|
||||
|
||||
/// <summary>
|
||||
/// Collects what deleting a local configuration plugin removes besides the plugin directory.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The configuration plugin about to be deleted.</param>
|
||||
/// <returns>
|
||||
/// The summary shown to the user before the deletion starts. It is empty when the plugin is not
|
||||
/// running, because we cannot tell what an unloadable plugin had configured.
|
||||
/// </returns>
|
||||
public ConfigurationPluginDeleteSummary BuildConfigurationDeleteSummary(IAvailablePlugin plugin)
|
||||
{
|
||||
var configurationPlugin = PluginFactory.RunningPlugins.OfType<PluginConfiguration>().FirstOrDefault(candidate => candidate.Id == plugin.Id);
|
||||
if (configurationPlugin is null)
|
||||
return ConfigurationPluginDeleteSummary.EMPTY;
|
||||
|
||||
var configObjects = configurationPlugin.ConfigObjects.ToList();
|
||||
var configurationData = this.settingsManager.ConfigurationData;
|
||||
|
||||
// Both maps record which configuration plugin manages a setting. Everything this plugin owns
|
||||
// returns to its default value once the plugin is gone:
|
||||
var lockedSettings =
|
||||
configurationData.ManagedLockedConfigurations.Count(entry => entry.Value == plugin.Id) +
|
||||
configurationData.ManagedEditableDefaults.Count(entry => entry.Value.ConfigPluginId == plugin.Id);
|
||||
|
||||
return new(
|
||||
LlmProviders: CountObjects(PluginConfigurationObjectType.LLM_PROVIDER),
|
||||
TranscriptionProviders: CountObjects(PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER),
|
||||
EmbeddingProviders: CountObjects(PluginConfigurationObjectType.EMBEDDING_PROVIDER),
|
||||
DataSources: CountObjects(PluginConfigurationObjectType.DATA_SOURCE),
|
||||
ChatTemplates: CountObjects(PluginConfigurationObjectType.CHAT_TEMPLATE),
|
||||
Profiles: CountObjects(PluginConfigurationObjectType.PROFILE),
|
||||
DocumentAnalysisPolicies: CountObjects(PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY),
|
||||
LockedSettings: lockedSettings,
|
||||
MandatoryInfos: configurationPlugin.MandatoryInfos.Count,
|
||||
Introductions: configurationPlugin.Introductions.Count);
|
||||
|
||||
int CountObjects(PluginConfigurationObjectType type) => configObjects.Count(configObject => configObject.Type == type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an assistant still owns running or canceling background work.
|
||||
/// </summary>
|
||||
@ -280,7 +323,7 @@ public sealed class PluginInstallService
|
||||
/// Delete result that contains success state, deleted plugin metadata, the original plugin directory,
|
||||
/// and a user-facing issue when deletion failed.
|
||||
/// </returns>
|
||||
public async Task<AssistantPluginDeleteResult> DeleteInstalledAssistantAsync(IAvailablePlugin plugin, CancellationToken token)
|
||||
public async Task<PluginDeleteResult> DeleteInstalledAssistantAsync(IAvailablePlugin plugin, CancellationToken token)
|
||||
{
|
||||
var eligibilityIssue = GetAssistantDeletionEligibilityIssue(plugin);
|
||||
if (!string.IsNullOrEmpty(eligibilityIssue))
|
||||
@ -304,7 +347,7 @@ public sealed class PluginInstallService
|
||||
if (this.HasActiveAssistantWork(plugin.Id))
|
||||
return DeleteError(plugin, pluginDirectory, TB("The assistant cannot be deleted while background work is still running."));
|
||||
|
||||
backupDirectory = CreateDeleteBackupDirectory(plugin);
|
||||
backupDirectory = CreateDeleteBackupDirectory(plugin, "assistant");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(backupDirectory)!);
|
||||
Directory.Move(pluginDirectory, backupDirectory);
|
||||
|
||||
@ -337,6 +380,63 @@ public sealed class PluginInstallService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a local configuration plugin directory.
|
||||
/// The directory gets moved to a backup dir outside the plugin root so the plugin loader cannot
|
||||
/// discover it during reload. On failure, the directory is restored.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do not remove the providers, data sources, chat templates, profiles, or locked settings of
|
||||
/// the plugin ourselves. The reload does that: it recognizes them as left over once their
|
||||
/// configuration plugin is gone, and it also deletes the related secrets from the OS keyring.
|
||||
/// </remarks>
|
||||
/// <param name="plugin">Configuration plugin metadata.</param>
|
||||
/// <param name="token">Cancellation token for the plugin reload.</param>
|
||||
/// <returns>
|
||||
/// Delete result that contains success state, deleted plugin metadata, the original plugin directory,
|
||||
/// and a user-facing issue when deletion failed.
|
||||
/// </returns>
|
||||
public async Task<PluginDeleteResult> DeleteInstalledConfigurationAsync(IAvailablePlugin plugin, CancellationToken token)
|
||||
{
|
||||
var eligibilityIssue = GetConfigurationDeletionEligibilityIssue(plugin);
|
||||
if (!string.IsNullOrEmpty(eligibilityIssue))
|
||||
return DeleteError(plugin, plugin.LocalPath, eligibilityIssue);
|
||||
|
||||
await this.installSemaphore.WaitAsync(token);
|
||||
var pluginDirectory = plugin.LocalPath;
|
||||
var backupDirectory = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// Check again under the semaphore: another operation might have changed the plugin state
|
||||
// while we were waiting:
|
||||
eligibilityIssue = GetConfigurationDeletionEligibilityIssue(plugin);
|
||||
if (!string.IsNullOrEmpty(eligibilityIssue))
|
||||
return DeleteError(plugin, pluginDirectory, eligibilityIssue);
|
||||
|
||||
backupDirectory = CreateDeleteBackupDirectory(plugin, "configuration");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(backupDirectory)!);
|
||||
Directory.Move(pluginDirectory, backupDirectory);
|
||||
|
||||
await PluginFactory.LoadAll(token);
|
||||
|
||||
TryDeleteDirectory(backupDirectory, "configuration plugin delete backup", this.logger);
|
||||
this.logger.LogInformation($"Deleted configuration plugin '{plugin.Name}' ({plugin.Id}) from '{pluginDirectory}'.");
|
||||
return new(true, plugin.Id, plugin.Name, pluginDirectory, string.Empty);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.logger.LogError(e, $"Failed to delete configuration plugin '{plugin.Name}' ({plugin.Id}) from '{pluginDirectory}'.");
|
||||
|
||||
await this.TryRestoreDeletedConfigurationPluginAsync(plugin, pluginDirectory, backupDirectory, token);
|
||||
return DeleteError(plugin, pluginDirectory, string.Format(TB("Unexpected error: {0}"), e.Message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.installSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates installed assistant plugin <c>plugin.lua</c> file.
|
||||
/// The edited Lua code is validated from the provided string before it is written,
|
||||
@ -643,6 +743,34 @@ public sealed class PluginInstallService
|
||||
: TB("The assistant plugin directory does not exist.");
|
||||
}
|
||||
|
||||
private static string GetConfigurationDeletionEligibilityIssue(IAvailablePlugin plugin)
|
||||
{
|
||||
if (plugin.Type is not PluginType.CONFIGURATION)
|
||||
return TB("Only configuration plugins can be deleted this way.");
|
||||
|
||||
if (plugin.IsInternal)
|
||||
return TB("Internal configuration plugins cannot be deleted.");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(plugin.LocalPath))
|
||||
return TB("The configuration plugin has no local directory.");
|
||||
|
||||
//
|
||||
// We decide by the plugin path, not by IsManagedByConfigServer. That value comes from the
|
||||
// plugin's own DEPLOYED_USING_CONFIG_SERVER field: a locally placed plugin could declare
|
||||
// itself managed and would then be impossible to remove through the user interface, which
|
||||
// is exactly the situation this deletion is meant to resolve.
|
||||
//
|
||||
if (PluginFactory.IsEnterpriseConfigurationPath(plugin.LocalPath))
|
||||
return TB("Configuration plugins deployed by your organization cannot be deleted.");
|
||||
|
||||
if (!PluginFactory.IsInsidePluginsRoot(plugin.LocalPath))
|
||||
return TB("The configuration plugin directory is outside the plugins directory.");
|
||||
|
||||
return Directory.Exists(plugin.LocalPath)
|
||||
? string.Empty
|
||||
: TB("The configuration plugin directory does not exist.");
|
||||
}
|
||||
|
||||
private void TryDeleteStagingDirectory(string stagingDirectory) => TryDeleteDirectory(stagingDirectory, "assistant plugin staging", this.logger);
|
||||
|
||||
private static string DetermineFinalDirectory(string assistantPluginsRoot, PluginAssistants assistantPlugin)
|
||||
@ -759,10 +887,10 @@ public sealed class PluginInstallService
|
||||
return string.Equals(firstPath, secondPath, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string CreateDeleteBackupDirectory(IAvailablePlugin plugin)
|
||||
private static string CreateDeleteBackupDirectory(IAvailablePlugin plugin, string pluginKind)
|
||||
{
|
||||
var backupRoot = Path.Join(SettingsManager.DataDirectory, DELETE_BACKUP_DIRECTORY);
|
||||
return Path.Join(backupRoot, $"assistant-{plugin.Id:N}-{Guid.NewGuid():N}");
|
||||
return Path.Join(backupRoot, $"{pluginKind}-{plugin.Id:N}-{Guid.NewGuid():N}");
|
||||
}
|
||||
|
||||
private static string CreateInstallBackupDirectory(IPluginMetadata plugin)
|
||||
@ -796,6 +924,22 @@ public sealed class PluginInstallService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryRestoreDeletedConfigurationPluginAsync(IAvailablePlugin plugin, string pluginDirectory, string backupDirectory, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(pluginDirectory) && Directory.Exists(backupDirectory))
|
||||
Directory.Move(backupDirectory, pluginDirectory);
|
||||
|
||||
// The reload restores everything the plugin configured, because it is back in place:
|
||||
await PluginFactory.LoadAll(token);
|
||||
}
|
||||
catch (Exception restoreException)
|
||||
{
|
||||
this.logger.LogError(restoreException, $"Failed to restore configuration plugin '{plugin.Name}' ({plugin.Id}) after a failed delete.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TryRestoreEditedAssistantPluginAsync(string pluginFile, string backupFile, CancellationToken token)
|
||||
{
|
||||
try
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
- Added the option to import plugins by dropping a plugin archive onto the plugin page.
|
||||
- Added the dedicated file extension `.mwplugin` for plugin archives.
|
||||
- Added an option for organizations to disable importing, sharing, and exporting plugins.
|
||||
- Added a delete button for configuration plugins you placed yourself. Until now, such a plugin could only be removed from the data directory by hand, because configuration plugins have no on/off switch. Before deleting, AI Studio lists what disappears with it, such as providers, data sources, and settings that return to their default. Configurations deployed by your IT department cannot be deleted.
|
||||
- Added a priority for configuration plugins. Organizations that deploy several configurations can now decide which one wins: a configuration with a higher priority overrides the settings and providers of a lower one. This allows a company-wide base configuration that each department refines for itself.
|
||||
- Improved how your organization's configuration behaves when a configuration plugin is present but cannot be loaded, e.g. because of an error in the plugin. Such a plugin still manages your app, so its settings, providers, data sources, profiles, and chat templates now stay in place instead of being removed.
|
||||
- Changed how approvals for assistant plugins combine when your organization deploys several configurations. They now add up, so a department can approve additional assistant plugins without repeating the approvals of the company-wide configuration. Previously, the last configuration replaced all earlier approvals, which silently required a new security check for those assistants.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user