Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions app/MindWork AI Studio/Assistants/I18N/allTexts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3589,6 +3589,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2036185364"] = "Code"
-- plus {0} image(s), which is more than the {1} this model accepts
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2059172343"] = "plus {0} image(s), which is more than the {1} this model accepts"

-- Please enter a chat name.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2301651387"] = "Please enter a chat name."

-- Italic
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2377171085"] = "Italic"

Expand All @@ -3601,6 +3604,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2670286472"] = "Profile u
-- The selected provider is not allowed in this chat due to data security or confidence-level requirements.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2672162875"] = "The selected provider is not allowed in this chat due to data security or confidence-level requirements."

-- Duplicate Chat
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2762849660"] = "Duplicate Chat"

-- {0} (copy)
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2930606011"] = "{0} (copy)"

-- Bulleted List
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2957125464"] = "Bulleted List"

Expand All @@ -3613,12 +3622,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3045856778"] = "Move Chat
-- {0} tokens
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3244065777"] = "{0} tokens"

-- Please enter a name for the copy of your chat '{0}':
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3323676840"] = "Please enter a name for the copy of your chat '{0}':"

-- plus {0} image(s), which cannot be counted
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3619858297"] = "plus {0} image(s), which cannot be counted"

-- Select a provider first
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3654197869"] = "Select a provider first"

-- Chat Name
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3891063690"] = "Chat Name"

-- Start new chat in workspace '{0}'
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3928697643"] = "Start new chat in workspace '{0}'"

Expand All @@ -3631,9 +3646,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4113970938"] = "Start tem
-- Heading
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4231005109"] = "Heading"

-- Duplicate
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4231201590"] = "Duplicate"

-- Please select the workspace where you want to move the chat to.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T474393241"] = "Please select the workspace where you want to move the chat to."

-- Duplicate this chat & continue in the copy.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T568087588"] = "Duplicate this chat & continue in the copy."

-- Move the chat to a workspace, or to another if it is already in one.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T636393754"] = "Move the chat to a workspace, or to another if it is already in one."

Expand Down Expand Up @@ -5338,6 +5359,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2446263209"] = "Workspace Na
-- Move to workspace
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2509305748"] = "Move to workspace"

-- Duplicate Chat
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2762849660"] = "Duplicate Chat"

-- {0} (copy)
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2930606011"] = "{0} (copy)"

-- Are you sure you want to delete the temporary chat '{0}'?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3043761007"] = "Are you sure you want to delete the temporary chat '{0}'?"

Expand All @@ -5353,6 +5380,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3249036008"] = "There is alr
-- Please enter a workspace name.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3288132732"] = "Please enter a workspace name."

-- Please enter a name for the copy of your chat '{0}':
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3323676840"] = "Please enter a name for the copy of your chat '{0}':"

-- Rename
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3355849203"] = "Rename"

Expand Down Expand Up @@ -5380,6 +5410,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4048389951"] = "Workspaces"
-- Disappearing Chats
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4201703117"] = "Disappearing Chats"

-- Are you sure you want to duplicate this chat? The copy is opened, so everything you wrote since you last saved this chat will be lost.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4222136922"] = "Are you sure you want to duplicate this chat? The copy is opened, so everything you wrote since you last saved this chat will be lost."

-- Duplicate
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4231201590"] = "Duplicate"

-- Please select the workspace where you want to move the chat to.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T474393241"] = "Please select the workspace where you want to move the chat to."

Expand Down
7 changes: 7 additions & 0 deletions app/MindWork AI Studio/Components/ChatComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@
<ChatTemplateSelection MarginLeft="" CanChatThreadBeUsedForTemplate="@this.CanThreadBeSaved" CurrentChatThread="@this.ChatThread" CurrentChatTemplate="@this.currentChatTemplate" CurrentChatTemplateChanged="@this.ChatTemplateWasChanged"/>


@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is not WorkspaceStorageBehavior.DISABLE_WORKSPACES)
{
<MudTooltip Text="@T("Duplicate this chat & continue in the copy.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@Icons.Material.Filled.ContentCopy" Disabled="@(!this.CanThreadBeSaved || this.IsCurrentChatStreaming)" OnClick="@this.DuplicateCurrentChat"/>
</MudTooltip>
}

@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
{
<MudTooltip Text="@T("Delete this chat & start a new one.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
Expand Down
43 changes: 43 additions & 0 deletions app/MindWork AI Studio/Components/ChatComponent.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,49 @@ private async Task StartNewChat(bool useSameWorkspace = false, bool deletePrevio
await this.ChatThreadChanged.InvokeAsync(this.ChatThread);
}

/// <summary>
/// Copies the chat which is open into a second one and continues in that one.
/// </summary>
/// <remarks>
/// Copied is the chat as it stands on the screen, not the state which was stored last, so a
/// sentence somebody wrote a moment ago is part of the copy. That is also why nothing is asked
/// about unsaved changes here, unlike everywhere else which leaves a chat behind: none of them
/// are lost, they are what is being copied.
/// </remarks>
private async Task DuplicateCurrentChat()
{
if (this.ChatThread is null || this.IsCurrentChatStreaming)
return;

var dialogParameters = new DialogParameters<SingleInputDialog>
{
{ x => x.Message, string.Format(T("Please enter a name for the copy of your chat '{0}':"), this.ChatThread.Name) },
{ x => x.InputHeaderText, T("Chat Name") },
{ x => x.UserInput, string.Format(T("{0} (copy)"), this.ChatThread.Name) },
{ x => x.ConfirmText, T("Duplicate") },
{ x => x.ConfirmColor, Color.Info },
{ x => x.AllowEmptyInput, false },
{ x => x.EmptyInputErrorMessage, T("Please enter a chat name.") },
};

var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>(T("Duplicate Chat"), dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result;
if (dialogResult is null || dialogResult.Canceled)
return;

var copy = await WorkspaceBehaviour.DuplicateChatAsync(this.ChatThread, (dialogResult.Data as string)!);
if (copy is null)
return;

this.ChatThread = copy;
this.hasUnsavedChanges = false;

await this.SyncForegroundChatAsync();
this.MarkCurrentChatAsLoadedParameter();
await this.SyncWorkspaceHeaderWithChatThreadAsync();
await this.ChatThreadChanged.InvokeAsync(this.ChatThread);
}

private async Task MoveChatToWorkspace()
{
if(this.ChatThread is null)
Expand Down
4 changes: 4 additions & 0 deletions app/MindWork AI Studio/Components/Workspaces.razor
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ else
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Medium" Color="Color.Inherit" Disabled="@this.IsChatTreeItemBusy(treeItem)" OnClick="@(() => this.RenameChatAsync(treeItem.Path))"/>
</MudTooltip>

<MudTooltip Text="@T("Duplicate")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@Icons.Material.Filled.ContentCopy" Size="Size.Medium" Color="Color.Inherit" Disabled="@this.IsChatTreeItemBusy(treeItem)" OnClick="@(() => this.DuplicateChatAsync(treeItem.Path))"/>
</MudTooltip>

<MudTooltip Text="@T("Delete")" Placement="@WORKSPACE_ITEM_TOOLTIP_PLACEMENT">
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Medium" Color="Color.Error" Disabled="@this.IsChatTreeItemBusy(treeItem)" OnClick="@(() => this.DeleteChatAsync(treeItem.Path))"/>
</MudTooltip>
Expand Down
58 changes: 58 additions & 0 deletions app/MindWork AI Studio/Components/Workspaces.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,64 @@ public async Task DeleteChatAsync(string? chatPath, bool askForConfirmation = tr
}
}

/// <summary>
/// Copies a chat of the tree into a second one and opens it.
/// </summary>
/// <remarks>
/// Two questions in a row, and only the second one is always asked. The first is the one every
/// other way out of a chat asks -- whether unsaved changes may be lost -- because the copy is
/// opened once it exists. The second asks what the copy is called, so that two chats of the
/// same name do not end up next to each other in the tree.
/// </remarks>
/// <param name="chatPath">The directory of the chat to copy.</param>
private async Task DuplicateChatAsync(string? chatPath)
{
var chat = await this.LoadChatAsync(chatPath, false);
if (chat is null)
return;

if (this.AIJobService.IsChatGenerationActive(chat.ChatId))
return;

if (await MessageBus.INSTANCE.SendMessageUseFirstResult<bool, bool>(this, Event.HAS_CHAT_UNSAVED_CHANGES))
{
var unsavedDialogParameters = new DialogParameters<ConfirmDialog>
{
{ x => x.Message, T("Are you sure you want to duplicate this chat? The copy is opened, so everything you wrote since you last saved this chat will be lost.") },
};

var unsavedDialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Duplicate Chat"), unsavedDialogParameters, DialogOptions.FULLSCREEN);
var unsavedDialogResult = await unsavedDialogReference.Result;
if (unsavedDialogResult is null || unsavedDialogResult.Canceled)
return;
}

var dialogParameters = new DialogParameters<SingleInputDialog>
{
{ x => x.Message, string.Format(T("Please enter a name for the copy of your chat '{0}':"), chat.Name) },
{ x => x.InputHeaderText, T("Chat Name") },
{ x => x.UserInput, string.Format(T("{0} (copy)"), chat.Name) },
{ x => x.ConfirmText, T("Duplicate") },
{ x => x.ConfirmColor, Color.Info },
{ x => x.AllowEmptyInput, false },
{ x => x.EmptyInputErrorMessage, T("Please enter a chat name.") },
};

var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>(T("Duplicate Chat"), dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result;
if (dialogResult is null || dialogResult.Canceled)
return;

var copy = await WorkspaceBehaviour.DuplicateChatAsync(chat, (dialogResult.Data as string)!);
if (copy is null)
return;

await this.LoadTreeItemsAsync(startPrefetch: false);

this.CurrentChatThread = copy;
await this.CurrentChatThreadChanged.InvokeAsync(this.CurrentChatThread);
}

private async Task RenameChatAsync(string? chatPath)
{
var chat = await this.LoadChatAsync(chatPath, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3591,6 +3591,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2036185364"] = "Code"
-- plus {0} image(s), which is more than the {1} this model accepts
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2059172343"] = "plus {0} Bild(er), also mehr als die {1}, die dieses Modell akzeptiert"

-- Please enter a chat name.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2301651387"] = "Bitte geben Sie einen Namen für diesen Chat ein."

-- Italic
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2377171085"] = "Kursiv"

Expand All @@ -3603,6 +3606,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2670286472"] = "Die Profi
-- The selected provider is not allowed in this chat due to data security or confidence-level requirements.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2672162875"] = "Der ausgewählte Anbieter ist in diesem Chat aufgrund der Datensicherheit oder der Anforderungen an das Vertrauensniveau nicht zulässig."

-- Duplicate Chat
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2762849660"] = "Chat duplizieren"

-- {0} (copy)
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2930606011"] = "{0} (Kopie)"

-- Bulleted List
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T2957125464"] = "Aufzählungszeichen"

Expand All @@ -3615,12 +3624,18 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3045856778"] = "Chat in d
-- {0} tokens
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3244065777"] = "{0} Token"

-- Please enter a name for the copy of your chat '{0}':
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3323676840"] = "Bitte geben Sie einen Namen für die Kopie Ihres Chats „{0}“ ein:"

-- plus {0} image(s), which cannot be counted
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3619858297"] = "zuzüglich {0} Bild(er), die nicht gezählt werden können"

-- Select a provider first
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3654197869"] = "Wähle zuerst einen Anbieter aus"

-- Chat Name
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3891063690"] = "Name des Chat"

-- Start new chat in workspace "{0}"
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T3928697643"] = "Neuen Chat im Arbeitsbereich '{0}' starten"

Expand All @@ -3633,9 +3648,15 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4113970938"] = "Neuen sel
-- Heading
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4231005109"] = "Überschrift"

-- Duplicate
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T4231201590"] = "Duplizieren"

-- Please select the workspace where you want to move the chat to.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T474393241"] = "Bitte wählen Sie den Arbeitsbereich aus, in den Sie den Chat verschieben möchten."

-- Duplicate this chat & continue in the copy.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T568087588"] = "Diesen Chat duplizieren und in der Kopie weiterarbeiten."

-- Move the chat to a workspace, or to another if it is already in one.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CHATCOMPONENT::T636393754"] = "Verschieben Sie den Chat in einen Arbeitsbereich oder in einen anderen, falls er sich bereits in einem befindet."

Expand Down Expand Up @@ -5340,6 +5361,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2446263209"] = "Name des Arb
-- Move to workspace
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2509305748"] = "In einen Arbeitsbereich verschieben"

-- Duplicate Chat
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2762849660"] = "Chat duplizieren"

-- {0} (copy)
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T2930606011"] = "{0} (Kopie)"

-- Are you sure you want to delete the chat '{0}'?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3043761007"] = "Sind Sie sicher, dass Sie den Chat „{0}“ löschen möchten?"

Expand All @@ -5355,6 +5382,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3249036008"] = "Es gibt bere
-- Please enter a workspace name.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3288132732"] = "Bitte geben Sie einen Namen für diesen Arbeitsbereich ein."

-- Please enter a name for the copy of your chat '{0}':
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3323676840"] = "Bitte geben Sie einen Namen für die Kopie Ihres Chats „{0}“ ein:"

-- Rename
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T3355849203"] = "Umbenennen"

Expand Down Expand Up @@ -5382,6 +5412,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4048389951"] = "Arbeitsberei
-- Disappearing Chats
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4201703117"] = "Selbstlöschende Chats"

-- Are you sure you want to duplicate this chat? The copy is opened, so everything you wrote since you last saved this chat will be lost.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4222136922"] = "Möchten Sie diesen Chat wirklich duplizieren? Die Kopie wird geöffnet; alles, was Sie seit dem letzten Speichern geschrieben haben, geht dabei verloren."

-- Duplicate
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T4231201590"] = "Duplizieren"

-- Please select the workspace where you want to move the chat to.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::WORKSPACES::T474393241"] = "Bitte wählen Sie den Arbeitsbereich aus, in den Sie den Chat verschieben möchten."

Expand Down
Loading
Loading