mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-22 11:38:28 +00:00
Logic for closing active tabs
This commit is contained in:
parent
5a9897dbfa
commit
fbabf96463
9 changed files with 127 additions and 30 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package ee.carlrobert.codegpt.client;
|
||||
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.openai.client.completion.CompletionEventListener;
|
||||
|
|
@ -7,12 +8,14 @@ import java.util.function.Consumer;
|
|||
|
||||
public class EventListener implements CompletionEventListener {
|
||||
|
||||
private final Conversation conversation;
|
||||
private final Message message;
|
||||
private final Consumer<String> onAppend;
|
||||
private final Runnable onStopGenerating;
|
||||
private final boolean isRetry;
|
||||
|
||||
public EventListener(Message message, Consumer<String> onAppend, Runnable onStopGenerating, boolean isRetry) {
|
||||
public EventListener(Conversation conversation, Message message, Consumer<String> onAppend, Runnable onStopGenerating, boolean isRetry) {
|
||||
this.conversation = conversation;
|
||||
this.onStopGenerating = onStopGenerating;
|
||||
this.onAppend = onAppend;
|
||||
this.message = message;
|
||||
|
|
@ -34,10 +37,9 @@ public class EventListener implements CompletionEventListener {
|
|||
|
||||
private void saveConversation(String response) {
|
||||
var conversationsState = ConversationsState.getInstance();
|
||||
var conversation = conversationsState.getOrStartNew();
|
||||
var conversationMessages = conversation.getMessages();
|
||||
|
||||
if (isRetry) {
|
||||
if (isRetry && !conversationMessages.isEmpty()) {
|
||||
conversationMessages.remove(conversationMessages.size() - 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ public class ConversationsState implements PersistentStateComponent<Conversation
|
|||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.filter(it -> conversationId.equals(it.getId()))
|
||||
.filter(item -> item.getId().equals(conversationId))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
package ee.carlrobert.codegpt.toolwindow;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.client.ClientProvider;
|
||||
import ee.carlrobert.codegpt.client.CompletionRequestProvider;
|
||||
import ee.carlrobert.codegpt.client.EventListener;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.SwingWorker;
|
||||
import okhttp3.sse.EventSource;
|
||||
|
||||
|
|
@ -18,18 +17,20 @@ public class ToolWindowService {
|
|||
public void startRequest(
|
||||
String prompt,
|
||||
SyntaxTextArea textArea,
|
||||
Project project,
|
||||
boolean isRetry,
|
||||
ChatToolWindowTabPanel toolWindow,
|
||||
Conversation conversation) {
|
||||
Conversation conversation,
|
||||
Runnable onStop,
|
||||
Consumer<EventSource> onStart,
|
||||
Runnable onScrollToBottom) {
|
||||
var conversationMessage = new Message(prompt);
|
||||
|
||||
new SwingWorker<Void, String>() {
|
||||
protected Void doInBackground() {
|
||||
var eventListener = new EventListener(
|
||||
conversation,
|
||||
conversationMessage,
|
||||
textArea::append,
|
||||
() -> toolWindow.stopGenerating(prompt, textArea, project),
|
||||
onStop,
|
||||
isRetry) {
|
||||
public void onMessage(String message) {
|
||||
publish(message);
|
||||
|
|
@ -46,7 +47,7 @@ public class ToolWindowService {
|
|||
call = ClientProvider.getTextCompletionClient().stream(
|
||||
requestProvider.buildTextCompletionRequest(settings.textCompletionBaseModel), eventListener);
|
||||
}
|
||||
toolWindow.displayGenerateButton(call::cancel);
|
||||
onStart.accept(call);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ public class ToolWindowService {
|
|||
try {
|
||||
textArea.append(text);
|
||||
conversationMessage.setResponse(textArea.getText());
|
||||
toolWindow.scrollToBottom();
|
||||
onScrollToBottom.run();
|
||||
} catch (Exception e) {
|
||||
textArea.append("Something went wrong. Please try again later.");
|
||||
throw new RuntimeException(e);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public class ChatContentManagerService {
|
|||
|
||||
public void resetTabbedPane(@NotNull Project project) {
|
||||
tryFindChatTabbedPane(project).ifPresent(tabbedPane -> {
|
||||
tabbedPane.removeAll();
|
||||
tabbedPane.clearAll();
|
||||
var tabPanel = new ChatToolWindowTabPanel(project);
|
||||
tabPanel.displayLandingView();
|
||||
tabbedPane.addNewTab(tabPanel);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package ee.carlrobert.codegpt.toolwindow.chat;
|
|||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class ChatTabbedPane extends JBTabbedPane {
|
||||
|
||||
|
|
@ -19,10 +22,24 @@ public class ChatTabbedPane extends JBTabbedPane {
|
|||
}
|
||||
|
||||
public void addNewTab(ChatToolWindowTabPanel toolWindowPanel) {
|
||||
super.addTab("Chat " + (getTabCount() + 1), toolWindowPanel.getContent());
|
||||
var tabIndex = getTabCount() - 1;
|
||||
super.setSelectedIndex(tabIndex);
|
||||
activeTabMapping.put(tabIndex, toolWindowPanel);
|
||||
var tabIndices = activeTabMapping.keySet().toArray(new Integer[0]);
|
||||
var nextIndex = 0;
|
||||
for (Integer val : tabIndices) {
|
||||
if (val == nextIndex) {
|
||||
nextIndex++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var title = "Chat " + (nextIndex + 1);
|
||||
super.insertTab(title, null, toolWindowPanel.getContent(), null, nextIndex);
|
||||
activeTabMapping.put(nextIndex, toolWindowPanel);
|
||||
super.setSelectedIndex(nextIndex);
|
||||
|
||||
if (nextIndex > 0) {
|
||||
setTabComponentAt(nextIndex, createCloseableTabButtonPanel(title, nextIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Integer> tryFindActiveConversationIndex(UUID conversationId) {
|
||||
|
|
@ -39,4 +56,34 @@ public class ChatTabbedPane extends JBTabbedPane {
|
|||
}
|
||||
return ConversationsState.getInstance().getConversation(toolWindowPanel.getConversationId());
|
||||
}
|
||||
|
||||
private JPanel createCloseableTabButtonPanel(String title, int tabIndex) {
|
||||
var button = new CloseableTabButton(title);
|
||||
button.addActionListener(new CloseActionListener(title, tabIndex));
|
||||
return button.getComponent();
|
||||
}
|
||||
|
||||
class CloseActionListener implements ActionListener {
|
||||
|
||||
private final String title;
|
||||
private final int tabMappingIndex;
|
||||
|
||||
public CloseActionListener(String title, int tabMappingIndex) {
|
||||
this.title = title;
|
||||
this.tabMappingIndex = tabMappingIndex;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
var tabIndex = indexOfTab(title);
|
||||
if (tabIndex >= 0) {
|
||||
removeTabAt(tabIndex);
|
||||
activeTabMapping.remove(tabMappingIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
removeAll();
|
||||
activeTabMapping.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,11 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
setToolbar(createActionToolbar(project, tabbedPane).getComponent());
|
||||
setContent(tabbedPane);
|
||||
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
if (contentManagerService.isChatTabSelected(toolWindow.getContentManager())) {
|
||||
var conversation = ConversationsState.getCurrentConversation();
|
||||
if (conversation == null) {
|
||||
tabPanel.displayLandingView();
|
||||
} else {
|
||||
tabPanel.displayConversation(conversation);
|
||||
}
|
||||
var conversation = ConversationsState.getCurrentConversation();
|
||||
if (conversation == null) {
|
||||
tabPanel.displayLandingView();
|
||||
} else {
|
||||
tabPanel.displayConversation(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import java.awt.event.MouseAdapter;
|
|||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
|
|
@ -45,7 +46,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
public class ChatToolWindowTabPanel {
|
||||
|
||||
private static final List<SyntaxTextArea> textAreas = new ArrayList<>();
|
||||
private final List<SyntaxTextArea> textAreas = new ArrayList<>();
|
||||
private final Project project;
|
||||
private JPanel chatGptToolWindowContent;
|
||||
private ScrollPane scrollPane;
|
||||
|
|
@ -130,10 +131,15 @@ public class ChatToolWindowTabPanel {
|
|||
addTextArea(textArea);
|
||||
}
|
||||
|
||||
var conversation = ConversationsState.getInstance().getOrStartNew();
|
||||
setConversationId(conversation.getId());
|
||||
var conversation = ConversationsState.getInstance().getConversation(conversationId);
|
||||
if (conversation.isEmpty()) {
|
||||
conversation = Optional.of(ConversationsState.getInstance().startConversation());
|
||||
}
|
||||
project.getService(ToolWindowService.class)
|
||||
.startRequest(prompt, textArea, project, isRetry, this, conversation);
|
||||
.startRequest(prompt, textArea, isRetry, conversation.get(),
|
||||
() -> stopGenerating(prompt, textArea, project),
|
||||
(eventSource) -> displayGenerateButton(eventSource::cancel),
|
||||
this::scrollToBottom);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class CloseableTabButton extends JButton {
|
||||
|
||||
private static final Icon closeIcon = AllIcons.Actions.Close;
|
||||
private final String title;
|
||||
|
||||
public CloseableTabButton(String title) {
|
||||
super(closeIcon);
|
||||
this.title = title;
|
||||
setBorder(BorderFactory.createEmptyBorder());
|
||||
setContentAreaFilled(false);
|
||||
setPreferredSize(new Dimension(closeIcon.getIconWidth(), closeIcon.getIconHeight()));
|
||||
setToolTipText("Close");
|
||||
setRolloverIcon(AllIcons.Actions.CloseHovered);
|
||||
}
|
||||
|
||||
public JPanel getComponent() {
|
||||
var panel = new JPanel(new GridBagLayout());
|
||||
panel.setOpaque(false);
|
||||
|
||||
var constraints = new GridBagConstraints();
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
constraints.weightx = 1;
|
||||
panel.add(new JLabel(title), constraints);
|
||||
|
||||
constraints.gridx++;
|
||||
constraints.weightx = 0;
|
||||
constraints.insets = JBUI.insetsLeft(8);
|
||||
panel.add(this, constraints);
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,6 @@ public class ConversationsToolWindow {
|
|||
|
||||
private void addContent(Conversation conversation) {
|
||||
var mainPanel = new RootConversationPanel(() -> {
|
||||
ConversationsState.getInstance().setCurrentConversation(conversation);
|
||||
changeSettings(conversation);
|
||||
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue