mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 17:32:11 +00:00
added possibility to open log file in file manager
This commit is contained in:
parent
11dd357a05
commit
d72b7c558e
@ -1648,6 +1648,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T174782740
|
||||
-- The log file does not exist: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1807514273"] = "The log file does not exist: {0}"
|
||||
|
||||
-- Could not open the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1828231197"] = "Could not open the log file location."
|
||||
|
||||
-- Other
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1849229205"] = "Other"
|
||||
|
||||
@ -1666,6 +1669,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T237835357
|
||||
-- No matching log lines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2511997530"] = "No matching log lines."
|
||||
|
||||
-- Could not open the log file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2533784927"] = "Could not open the log file location: {0}"
|
||||
|
||||
-- Source details
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2686813966"] = "Source details"
|
||||
|
||||
@ -1678,6 +1684,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T315262563
|
||||
-- Loading log file...
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T333036481"] = "Loading log file..."
|
||||
|
||||
-- Unknown error
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3461425987"] = "Unknown error"
|
||||
|
||||
-- The log file path is not available yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3686775689"] = "The log file path is not available yet."
|
||||
|
||||
@ -1696,12 +1705,18 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T397479987
|
||||
-- Usage log
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4031747274"] = "Usage log"
|
||||
|
||||
-- Open in folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4048746540"] = "Open in folder"
|
||||
|
||||
-- Log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4129341821"] = "Log file"
|
||||
|
||||
-- Log Viewer
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4130241777"] = "Log Viewer"
|
||||
|
||||
-- Opened the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4162897654"] = "Opened the log file location."
|
||||
|
||||
-- Show timestamps
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T469116133"] = "Show timestamps"
|
||||
|
||||
@ -8584,24 +8599,42 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Failed
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Failed to store the API key due to an API issue."
|
||||
|
||||
-- The runtime file manager endpoint returned '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2158262203"] = "The runtime file manager endpoint returned '{0}'."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Failed to delete the secret data due to an API issue."
|
||||
|
||||
-- The runtime file manager endpoint is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2486847754"] = "The runtime file manager endpoint is not available."
|
||||
|
||||
-- The runtime file manager endpoint failed without details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3082220817"] = "The runtime file manager endpoint failed without details."
|
||||
|
||||
-- Successfully copied the text to your clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3351807428"] = "Successfully copied the text to your clipboard"
|
||||
|
||||
-- The path does not exist and its parent folder could not be found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3606079336"] = "The path does not exist and its parent folder could not be found."
|
||||
|
||||
-- Failed to delete the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3658273365"] = "Failed to delete the API key due to an API issue."
|
||||
|
||||
-- Failed to copy the text to your clipboard.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3724548108"] = "Failed to copy the text to your clipboard."
|
||||
|
||||
-- The local file manager command failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T381756374"] = "The local file manager command failed: {0}"
|
||||
|
||||
-- Failed to get the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3875720022"] = "Failed to get the API key due to an API issue."
|
||||
|
||||
-- Failed to get the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T4007657575"] = "Failed to get the secret data due to an API issue."
|
||||
|
||||
-- The local file manager command did not start.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T613631541"] = "The local file manager command did not start."
|
||||
|
||||
-- No update found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::UPDATESERVICE::T1015418291"] = "No update found."
|
||||
|
||||
|
||||
@ -22,6 +22,9 @@
|
||||
</MudButton>
|
||||
}
|
||||
<MudNumericField T="int" Value="@this.maxLines" ValueChanged="@this.MaxLinesChanged" Label="@T("Max lines")" Variant="Variant.Outlined" Margin="Margin.Dense" Min="@MIN_MAX_LINES" Max="@MAX_MAX_LINES" Step="500" Class="log-viewer-number" />
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Default" StartIcon="@Icons.Material.Filled.FolderOpen" OnClick="@this.OpenCurrentLogInFileManager" Disabled="@(!this.CanOpenCurrentLogPath)">
|
||||
@T("Open in folder")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="@true" Wrap="@Wrap.Wrap" AlignItems="@AlignItems.Center" Spacing="2" Class="mb-1">
|
||||
|
||||
@ -34,6 +34,9 @@ public partial class AssistantLogViewer : MSGComponentBase
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private NavigationManager NavigationManager { get; init; } = null!;
|
||||
|
||||
@ -65,6 +68,8 @@ public partial class AssistantLogViewer : MSGComponentBase
|
||||
|
||||
private string CurrentLogPath => this.selectedLogFile is LogFileKind.APP ? this.logPaths.LogAppPath : this.logPaths.LogStartupPath;
|
||||
|
||||
private bool CanOpenCurrentLogPath => !string.IsNullOrWhiteSpace(this.CurrentLogPath);
|
||||
|
||||
private bool HasDropdownFilter => this.selectedLogLevels.Count > 0 || this.selectedLoggers.Count > 0 || this.selectedSourceDetails.Count > 0;
|
||||
|
||||
private bool HasActiveFilter => !string.IsNullOrWhiteSpace(this.filterText) || this.HasDropdownFilter;
|
||||
@ -203,6 +208,68 @@ public partial class AssistantLogViewer : MSGComponentBase
|
||||
await this.RefreshLogAsync();
|
||||
}
|
||||
|
||||
private async Task OpenCurrentLogInFileManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.logPaths = await this.RustService.GetLogPaths();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.Logger.LogWarning(e, "Could not refresh the log file paths before opening the file manager.");
|
||||
this.Snackbar.Add(T("The log file path is not available yet."), Severity.Warning, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.Folder;
|
||||
config.IconSize = Size.Large;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var path = this.CurrentLogPath;
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
this.Snackbar.Add(T("The log file path is not available yet."), Severity.Warning, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.Folder;
|
||||
config.IconSize = Size.Large;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
OpenPathResponse response;
|
||||
try
|
||||
{
|
||||
response = await this.RustService.OpenPathInFileManager(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.Logger.LogWarning(e, "Could not open the log file location in the file manager.");
|
||||
this.Snackbar.Add(T("Could not open the log file location."), Severity.Error, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.Folder;
|
||||
config.IconSize = Size.Large;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.Success)
|
||||
{
|
||||
this.Snackbar.Add(T("Opened the log file location."), Severity.Success, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.FolderOpen;
|
||||
config.IconSize = Size.Large;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var issue = string.IsNullOrWhiteSpace(response.Issue) ? T("Unknown error") : response.Issue;
|
||||
this.Snackbar.Add(string.Format(T("Could not open the log file location: {0}"), issue), Severity.Error, config =>
|
||||
{
|
||||
config.Icon = Icons.Material.Filled.Folder;
|
||||
config.IconSize = Size.Large;
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearFilters()
|
||||
{
|
||||
this.filterText = string.Empty;
|
||||
|
||||
@ -1650,6 +1650,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T174782740
|
||||
-- The log file does not exist: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1807514273"] = "Die Protokolldatei existiert nicht: {0}"
|
||||
|
||||
-- Could not open the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1828231197"] = "Konnte den Speicherort der Protokolldatei nicht öffnen."
|
||||
|
||||
-- Other
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1849229205"] = "Andere"
|
||||
|
||||
@ -1668,6 +1671,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T237835357
|
||||
-- No matching log lines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2511997530"] = "Keine passenden Protokollzeilen."
|
||||
|
||||
-- Could not open the log file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2533784927"] = "Konnte den Speicherort der Protokolldatei nicht öffnen: {0}"
|
||||
|
||||
-- Source details
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2686813966"] = "Quellendetails"
|
||||
|
||||
@ -1680,6 +1686,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T315262563
|
||||
-- Loading log file...
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T333036481"] = "Lade Protokolldatei..."
|
||||
|
||||
-- Unknown error
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3461425987"] = "Unbekannter Fehler"
|
||||
|
||||
-- The log file path is not available yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3686775689"] = "Der Pfad zur Protokolldatei ist noch nicht verfügbar."
|
||||
|
||||
@ -1698,12 +1707,18 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T397479987
|
||||
-- Usage log
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4031747274"] = "Nutzungsprotokoll"
|
||||
|
||||
-- Open in folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4048746540"] = "Im Ordner öffnen"
|
||||
|
||||
-- Log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4129341821"] = "Protokolldatei"
|
||||
|
||||
-- Log Viewer
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4130241777"] = "Protokollanzeige"
|
||||
|
||||
-- Opened the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4162897654"] = "Der Speicherort der Protokolldatei wurde geöffnet."
|
||||
|
||||
-- Show timestamps
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T469116133"] = "Zeitstempel anzeigen"
|
||||
|
||||
@ -8586,24 +8601,42 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Fehler
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Fehler beim Speichern des API-Schlüssels aufgrund eines API-Problems."
|
||||
|
||||
-- The runtime file manager endpoint returned '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2158262203"] = "Der Laufzeit-Dateimanager-Endpunkt hat '{0}' zurückgegeben."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Das Löschen der geheimen Daten ist aufgrund eines API-Problems fehlgeschlagen."
|
||||
|
||||
-- The runtime file manager endpoint is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2486847754"] = "Der Laufzeit-Dateimanager-Endpunkt ist nicht verfügbar."
|
||||
|
||||
-- The runtime file manager endpoint failed without details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3082220817"] = "Der Laufzeit-Dateimanager-Endpunkt ist ohne Details fehlgeschlagen."
|
||||
|
||||
-- Successfully copied the text to your clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3351807428"] = "Der Text wurde erfolgreich in die Zwischenablage kopiert."
|
||||
|
||||
-- The path does not exist and its parent folder could not be found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3606079336"] = "Der Pfad existiert nicht, und der übergeordnete Ordner konnte nicht gefunden werden."
|
||||
|
||||
-- Failed to delete the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3658273365"] = "Das API-Schlüssel konnte aufgrund eines API-Problems nicht gelöscht werden."
|
||||
|
||||
-- Failed to copy the text to your clipboard.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3724548108"] = "Der Text konnte nicht in die Zwischenablage kopiert werden."
|
||||
|
||||
-- The local file manager command failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T381756374"] = "Der Befehl des lokalen Dateimanagers ist fehlgeschlagen: {0}"
|
||||
|
||||
-- Failed to get the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3875720022"] = "Der API-Schlüssel konnte aufgrund eines API-Problems nicht abgerufen werden."
|
||||
|
||||
-- Failed to get the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T4007657575"] = "Abrufen der geheimen Daten aufgrund eines API-Problems fehlgeschlagen."
|
||||
|
||||
-- The local file manager command did not start.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T613631541"] = "Der Befehl des lokalen Dateimanagers wurde nicht gestartet."
|
||||
|
||||
-- No update found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::UPDATESERVICE::T1015418291"] = "Kein Update gefunden."
|
||||
|
||||
|
||||
@ -1650,6 +1650,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T174782740
|
||||
-- The log file does not exist: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1807514273"] = "The log file does not exist: {0}"
|
||||
|
||||
-- Could not open the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1828231197"] = "Could not open the log file location."
|
||||
|
||||
-- Other
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T1849229205"] = "Other"
|
||||
|
||||
@ -1668,6 +1671,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T237835357
|
||||
-- No matching log lines.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2511997530"] = "No matching log lines."
|
||||
|
||||
-- Could not open the log file location: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2533784927"] = "Could not open the log file location: {0}"
|
||||
|
||||
-- Source details
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T2686813966"] = "Source details"
|
||||
|
||||
@ -1680,6 +1686,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T315262563
|
||||
-- Loading log file...
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T333036481"] = "Loading log file..."
|
||||
|
||||
-- Unknown error
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3461425987"] = "Unknown error"
|
||||
|
||||
-- The log file path is not available yet.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T3686775689"] = "The log file path is not available yet."
|
||||
|
||||
@ -1698,12 +1707,18 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T397479987
|
||||
-- Usage log
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4031747274"] = "Usage log"
|
||||
|
||||
-- Open in folder
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4048746540"] = "Open in folder"
|
||||
|
||||
-- Log file
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4129341821"] = "Log file"
|
||||
|
||||
-- Log Viewer
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4130241777"] = "Log Viewer"
|
||||
|
||||
-- Opened the log file location.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T4162897654"] = "Opened the log file location."
|
||||
|
||||
-- Show timestamps
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LOGVIEWER::ASSISTANTLOGVIEWER::T469116133"] = "Show timestamps"
|
||||
|
||||
@ -8586,24 +8601,42 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1110203516"] = "Failed
|
||||
-- Failed to store the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T1704298921"] = "Failed to store the API key due to an API issue."
|
||||
|
||||
-- The runtime file manager endpoint returned '{0}'.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2158262203"] = "The runtime file manager endpoint returned '{0}'."
|
||||
|
||||
-- Failed to delete the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2303057928"] = "Failed to delete the secret data due to an API issue."
|
||||
|
||||
-- The runtime file manager endpoint is not available.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T2486847754"] = "The runtime file manager endpoint is not available."
|
||||
|
||||
-- The runtime file manager endpoint failed without details.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3082220817"] = "The runtime file manager endpoint failed without details."
|
||||
|
||||
-- Successfully copied the text to your clipboard
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3351807428"] = "Successfully copied the text to your clipboard"
|
||||
|
||||
-- The path does not exist and its parent folder could not be found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3606079336"] = "The path does not exist and its parent folder could not be found."
|
||||
|
||||
-- Failed to delete the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3658273365"] = "Failed to delete the API key due to an API issue."
|
||||
|
||||
-- Failed to copy the text to your clipboard.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3724548108"] = "Failed to copy the text to your clipboard."
|
||||
|
||||
-- The local file manager command failed: {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T381756374"] = "The local file manager command failed: {0}"
|
||||
|
||||
-- Failed to get the API key due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T3875720022"] = "Failed to get the API key due to an API issue."
|
||||
|
||||
-- Failed to get the secret data due to an API issue.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T4007657575"] = "Failed to get the secret data due to an API issue."
|
||||
|
||||
-- The local file manager command did not start.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::RUSTSERVICE::T613631541"] = "The local file manager command did not start."
|
||||
|
||||
-- No update found.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SERVICES::UPDATESERVICE::T1015418291"] = "No update found."
|
||||
|
||||
|
||||
3
app/MindWork AI Studio/Tools/Rust/OpenPathRequest.cs
Normal file
3
app/MindWork AI Studio/Tools/Rust/OpenPathRequest.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Tools.Rust;
|
||||
|
||||
public readonly record struct OpenPathRequest(string Path);
|
||||
3
app/MindWork AI Studio/Tools/Rust/OpenPathResponse.cs
Normal file
3
app/MindWork AI Studio/Tools/Rust/OpenPathResponse.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Tools.Rust;
|
||||
|
||||
public readonly record struct OpenPathResponse(bool Success, string Issue);
|
||||
@ -1,3 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools.Services;
|
||||
@ -84,4 +86,109 @@ public sealed partial class RustService
|
||||
|
||||
return await result.Content.ReadFromJsonAsync<FileSaveResponse>(this.jsonRustSerializerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<OpenPathResponse> OpenPathInFileManager(string path)
|
||||
{
|
||||
var runtimeResponse = await this.TryOpenPathInRuntimeFileManager(path);
|
||||
if (runtimeResponse.Success)
|
||||
return runtimeResponse;
|
||||
|
||||
var localResponse = this.TryOpenPathInLocalFileManager(path);
|
||||
if (localResponse.Success)
|
||||
return localResponse;
|
||||
|
||||
var issue = string.IsNullOrWhiteSpace(runtimeResponse.Issue)
|
||||
? localResponse.Issue
|
||||
: $"{runtimeResponse.Issue} {localResponse.Issue}";
|
||||
|
||||
return new OpenPathResponse(false, issue.Trim());
|
||||
}
|
||||
|
||||
private async Task<OpenPathResponse> TryOpenPathInRuntimeFileManager(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await this.http.PostAsJsonAsync("/open/path", new OpenPathRequest(path), this.jsonRustSerializerOptions);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
this.logger!.LogWarning("Failed to open a path in the file manager through the Rust runtime: '{StatusCode}'", result.StatusCode);
|
||||
return new OpenPathResponse(false, string.Format(TB("The runtime file manager endpoint returned '{0}'."), result.StatusCode));
|
||||
}
|
||||
|
||||
var response = await result.Content.ReadFromJsonAsync<OpenPathResponse>(this.jsonRustSerializerOptions);
|
||||
return response.Success
|
||||
? response
|
||||
: new OpenPathResponse(false, string.IsNullOrWhiteSpace(response.Issue) ? TB("The runtime file manager endpoint failed without details.") : response.Issue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.logger!.LogWarning(e, "Failed to open a path in the file manager through the Rust runtime.");
|
||||
return new OpenPathResponse(false, TB("The runtime file manager endpoint is not available."));
|
||||
}
|
||||
}
|
||||
|
||||
private OpenPathResponse TryOpenPathInLocalFileManager(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var target = ResolveFileManagerTarget(path);
|
||||
if (target is null)
|
||||
return new OpenPathResponse(false, TB("The path does not exist and its parent folder could not be found."));
|
||||
|
||||
using var process = Process.Start(CreateFileManagerStartInfo(target.Value));
|
||||
return process is null
|
||||
? new OpenPathResponse(false, TB("The local file manager command did not start."))
|
||||
: new OpenPathResponse(true, string.Empty);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.logger!.LogWarning(e, "Failed to open a path in the local file manager.");
|
||||
return new OpenPathResponse(false, string.Format(TB("The local file manager command failed: {0}"), e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
private static FileManagerTarget? ResolveFileManagerTarget(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
var requestedPath = path.Trim();
|
||||
if (File.Exists(requestedPath))
|
||||
return new FileManagerTarget(requestedPath, true);
|
||||
|
||||
if (Directory.Exists(requestedPath))
|
||||
return new FileManagerTarget(requestedPath, false);
|
||||
|
||||
var parent = Directory.GetParent(requestedPath)?.FullName;
|
||||
return !string.IsNullOrWhiteSpace(parent) && Directory.Exists(parent)
|
||||
? new FileManagerTarget(parent, false)
|
||||
: null;
|
||||
}
|
||||
|
||||
private static ProcessStartInfo CreateFileManagerStartInfo(FileManagerTarget target)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
var windowsInfo = new ProcessStartInfo("explorer.exe") { UseShellExecute = false };
|
||||
windowsInfo.ArgumentList.Add(target.RevealFile ? $"/select,{target.Path}" : target.Path);
|
||||
return windowsInfo;
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
var macOsInfo = new ProcessStartInfo("open") { UseShellExecute = false };
|
||||
if (target.RevealFile)
|
||||
macOsInfo.ArgumentList.Add("-R");
|
||||
|
||||
macOsInfo.ArgumentList.Add(target.Path);
|
||||
return macOsInfo;
|
||||
}
|
||||
|
||||
var linuxInfo = new ProcessStartInfo("xdg-open") { UseShellExecute = false };
|
||||
var directory = target.RevealFile ? Path.GetDirectoryName(target.Path) ?? target.Path : target.Path;
|
||||
linuxInfo.ArgumentList.Add(directory);
|
||||
return linuxInfo;
|
||||
}
|
||||
|
||||
private readonly record struct FileManagerTarget(string Path, bool RevealFile);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
- Improved update guidance for Flatpak installations and added an enterprise option that lets organizations manage updates entirely through their IT department.
|
||||
- Fixed an issue that could leave AI Studio unresponsive after waking the computer from sleep.
|
||||
- Fixed enterprise configuration plugins from Windows-created ZIP files not loading correctly on Linux when the ZIP contained plugin files inside a folder.
|
||||
- Fixed file extension handling so files are recognized correctly regardless of uppercase or lowercase letters in their extensions.
|
||||
- Fixed voice recording not starting on Linux.
|
||||
- Upgraded Rust to v1.97.0.
|
||||
- Upgraded Tauri to v2.11.5.
|
||||
|
||||
@ -2,10 +2,18 @@
|
||||
use axum::extract::Query;
|
||||
use axum::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::process::CommandExt;
|
||||
use tauri_plugin_dialog::{DialogExt, FileDialogBuilder};
|
||||
use crate::api_token::APIToken;
|
||||
use crate::app_window::MAIN_WINDOW;
|
||||
|
||||
/// Microsoft documents CREATE_NO_WINDOW as a process creation flag with value 0x08000000.
|
||||
#[cfg(windows)]
|
||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct PreviousDirectory {
|
||||
path: String,
|
||||
@ -36,6 +44,11 @@ pub struct SaveFileOptions {
|
||||
filter: Option<FileTypeFilter>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct OpenPathOptions {
|
||||
path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DirectorySelectionResponse {
|
||||
user_cancelled: bool,
|
||||
@ -60,6 +73,12 @@ pub struct FileSaveResponse {
|
||||
save_file_path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct OpenPathResponse {
|
||||
success: bool,
|
||||
issue: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct PreviousFile {
|
||||
file_path: String,
|
||||
@ -286,6 +305,55 @@ pub async fn save_file(_token: APIToken, payload: Json<SaveFileOptions>) -> Json
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn open_path_in_file_manager(
|
||||
_token: APIToken,
|
||||
payload: Json<OpenPathOptions>,
|
||||
) -> Json<OpenPathResponse> {
|
||||
let requested_path = PathBuf::from(payload.path.trim());
|
||||
if requested_path.as_os_str().is_empty() {
|
||||
return Json(OpenPathResponse {
|
||||
success: false,
|
||||
issue: String::from("The path is empty."),
|
||||
});
|
||||
}
|
||||
|
||||
let Some(target) = resolve_file_manager_target(&requested_path) else {
|
||||
let issue = format!(
|
||||
"The path does not exist and its parent folder could not be found: {}",
|
||||
requested_path.to_string_lossy(),
|
||||
);
|
||||
error!(Source = "Tauri"; "{issue}");
|
||||
return Json(OpenPathResponse {
|
||||
success: false,
|
||||
issue,
|
||||
});
|
||||
};
|
||||
|
||||
let mut command = create_file_manager_command(&target);
|
||||
|
||||
#[cfg(windows)]
|
||||
command.creation_flags(CREATE_NO_WINDOW);
|
||||
|
||||
match command.spawn() {
|
||||
Ok(_) => {
|
||||
info!("Opened file manager for path: {:?}", target.path);
|
||||
Json(OpenPathResponse {
|
||||
success: true,
|
||||
issue: String::new(),
|
||||
})
|
||||
}
|
||||
|
||||
Err(error) => {
|
||||
let issue = format!("Failed to open the file manager: {error}");
|
||||
error!(Source = "Tauri"; "{issue}");
|
||||
Json(OpenPathResponse {
|
||||
success: false,
|
||||
issue,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies an optional file type filter to a FileDialogBuilder.
|
||||
fn apply_filter<R: tauri::Runtime>(file_dialog: FileDialogBuilder<R>, filter: &Option<FileTypeFilter>) -> FileDialogBuilder<R> {
|
||||
match filter {
|
||||
@ -296,4 +364,68 @@ fn apply_filter<R: tauri::Runtime>(file_dialog: FileDialogBuilder<R>, filter: &O
|
||||
|
||||
None => file_dialog,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FileManagerTarget {
|
||||
path: PathBuf,
|
||||
reveal_file: bool,
|
||||
}
|
||||
|
||||
fn resolve_file_manager_target(requested_path: &Path) -> Option<FileManagerTarget> {
|
||||
if requested_path.is_file() {
|
||||
return Some(FileManagerTarget {
|
||||
path: requested_path.to_path_buf(),
|
||||
reveal_file: true,
|
||||
});
|
||||
}
|
||||
|
||||
if requested_path.is_dir() {
|
||||
return Some(FileManagerTarget {
|
||||
path: requested_path.to_path_buf(),
|
||||
reveal_file: false,
|
||||
});
|
||||
}
|
||||
|
||||
requested_path.parent()
|
||||
.filter(|parent| parent.is_dir())
|
||||
.map(|parent| FileManagerTarget {
|
||||
path: parent.to_path_buf(),
|
||||
reveal_file: false,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn create_file_manager_command(target: &FileManagerTarget) -> Command {
|
||||
let mut command = Command::new("explorer.exe");
|
||||
if target.reveal_file {
|
||||
command.arg(format!("/select,{}", target.path.to_string_lossy()));
|
||||
} else {
|
||||
command.arg(&target.path);
|
||||
}
|
||||
|
||||
command
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn create_file_manager_command(target: &FileManagerTarget) -> Command {
|
||||
let mut command = Command::new("open");
|
||||
if target.reveal_file {
|
||||
command.arg("-R");
|
||||
}
|
||||
|
||||
command.arg(&target.path);
|
||||
command
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
fn create_file_manager_command(target: &FileManagerTarget) -> Command {
|
||||
let mut command = Command::new("xdg-open");
|
||||
let directory = if target.reveal_file {
|
||||
target.path.parent().unwrap_or(&target.path)
|
||||
} else {
|
||||
&target.path
|
||||
};
|
||||
|
||||
command.arg(directory);
|
||||
command
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ pub fn start_runtime_api() {
|
||||
.route("/select/file", post(crate::file_actions::select_file))
|
||||
.route("/select/files", post(crate::file_actions::select_files))
|
||||
.route("/save/file", post(crate::file_actions::save_file))
|
||||
.route("/open/path", post(crate::file_actions::open_path_in_file_manager))
|
||||
.route("/secrets/get", post(crate::secret::get_secret))
|
||||
.route("/secrets/store", post(crate::secret::store_secret))
|
||||
.route("/secrets/delete", post(crate::secret::delete_secret))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user