mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-22 03:30:04 +00:00
You API integration (#203)
* Ability to configure custom service * Add example preset templates, rename module * Custom service client impl * Add YOU API integration * Remove/ignore generated antlr classes * Remove text completion models(deprecated) * Remove unused code, fix settings state sync * Display model name/icon in the tool window * Update chat history UI * Fix model/service sync * Clear plugin state * Fix minor bugs, add settings sync tests * UI changes * Separate model configuration * Add support for overriding the completion path * Update Find Bugs prompt
This commit is contained in:
parent
a860054360
commit
37af74ebdf
125 changed files with 1673 additions and 1537 deletions
|
|
@ -0,0 +1,36 @@
|
|||
package ee.carlrobert.codegpt.toolwindow;
|
||||
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBFont;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.llm.client.openai.completion.chat.OpenAIChatCompletionModel;
|
||||
import java.util.NoSuchElementException;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
public class ModelIconLabel extends JBLabel {
|
||||
|
||||
public ModelIconLabel(String clientCode, String modelCode) {
|
||||
if ("you.chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.YouIcon);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.OpenAIIcon);
|
||||
}
|
||||
if ("azure.chat.completion".equals(clientCode)) {
|
||||
setIcon(Icons.AzureIcon);
|
||||
}
|
||||
setText(formatModelName(modelCode));
|
||||
setFont(JBFont.small().asBold());
|
||||
setHorizontalAlignment(SwingConstants.LEADING);
|
||||
}
|
||||
|
||||
private String formatModelName(String modelCode) {
|
||||
try {
|
||||
return OpenAIChatCompletionModel.findByCode(modelCode).getDescription();
|
||||
} catch (NoSuchElementException e) {
|
||||
return modelCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.intellij.openapi.wm.ToolWindow;
|
|||
import com.intellij.openapi.wm.ToolWindowFactory;
|
||||
import com.intellij.ui.content.ContentManagerEvent;
|
||||
import com.intellij.ui.content.ContentManagerListener;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.contextual.ContextualChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.conversations.ConversationsToolWindow;
|
||||
import javax.swing.JComponent;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package ee.carlrobert.codegpt.toolwindow.chat;
|
|||
import static com.intellij.openapi.ui.Messages.OK;
|
||||
import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
|
@ -11,12 +12,21 @@ import com.intellij.ui.JBColor;
|
|||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
|
||||
import ee.carlrobert.codegpt.completions.SerpResult;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.credentials.AzureCredentialsManager;
|
||||
import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager;
|
||||
import ee.carlrobert.codegpt.settings.state.AzureSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.OpenAISettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.ModelIconLabel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.user.UserManager;
|
||||
import ee.carlrobert.codegpt.util.EditorUtils;
|
||||
import ee.carlrobert.codegpt.util.FileUtils;
|
||||
import ee.carlrobert.codegpt.util.OverlayUtils;
|
||||
|
|
@ -25,6 +35,7 @@ import java.awt.GridBagConstraints;
|
|||
import java.awt.GridBagLayout;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.swing.BoxLayout;
|
||||
|
|
@ -41,9 +52,10 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
private final JPanel rootPanel;
|
||||
private final ScrollablePanel scrollablePanel;
|
||||
private final Map<UUID, JPanel> visibleMessagePanels = new HashMap<>();
|
||||
private final Map<UUID, List<SerpResult>> serpResultsMapping = new HashMap<>();
|
||||
|
||||
protected final Project project;
|
||||
protected final UserTextArea userTextArea;
|
||||
protected final UserPromptTextArea userPromptTextArea;
|
||||
protected final ConversationService conversationService;
|
||||
protected @Nullable Conversation conversation;
|
||||
|
||||
|
|
@ -55,12 +67,12 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
this.conversationService = ConversationService.getInstance();
|
||||
this.rootPanel = new JPanel(new GridBagLayout());
|
||||
this.scrollablePanel = new ScrollablePanel();
|
||||
this.userTextArea = new UserTextArea(this::handleSubmit);
|
||||
this.userPromptTextArea = new UserPromptTextArea(this::handleSubmit);
|
||||
init();
|
||||
}
|
||||
|
||||
public void requestFocusForTextArea() {
|
||||
userTextArea.focus();
|
||||
userPromptTextArea.focus();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -113,6 +125,9 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
}
|
||||
|
||||
private boolean isCredentialSet() {
|
||||
if (SettingsState.getInstance().isUseYouService()) {
|
||||
return UserManager.getInstance().isAuthenticated();
|
||||
}
|
||||
if (SettingsState.getInstance().isUseAzureService()) {
|
||||
return AzureCredentialsManager.getInstance().isCredentialSet();
|
||||
}
|
||||
|
|
@ -141,6 +156,20 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
responsePanel.enableActions();
|
||||
conversationService.saveMessage(completeMessage, message, conversation, isRetry);
|
||||
stopStreaming(responseContainer);
|
||||
|
||||
var serpResults = serpResultsMapping.get(message.getId());
|
||||
var containsResults = serpResults != null && !serpResults.isEmpty();
|
||||
if (SettingsState.getInstance().isDisplayWebSearchResults()) {
|
||||
if (containsResults) {
|
||||
responseContainer.displaySerpResults(serpResults);
|
||||
}
|
||||
}
|
||||
|
||||
if (containsResults) {
|
||||
message.setSerpResults(serpResults.stream()
|
||||
.map(result -> new SerpResult(result.getUrl(), result.getName(), result.getSnippet(), result.getSnippetSource()))
|
||||
.collect(toList()));
|
||||
}
|
||||
});
|
||||
requestHandler.addTokensExceededListener(() -> SwingUtilities.invokeLater(() -> {
|
||||
var answer = OverlayUtils.showTokenLimitExceededDialog();
|
||||
|
|
@ -156,8 +185,11 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
responseContainer.displayError(error.getMessage());
|
||||
stopStreaming(responseContainer);
|
||||
});
|
||||
userTextArea.setRequestHandler(requestHandler);
|
||||
userTextArea.setSubmitEnabled(false);
|
||||
requestHandler.addSerpResultsListener(serpResults -> serpResultsMapping.put(message.getId(), serpResults.stream()
|
||||
.map(result -> new SerpResult(result.getUrl(), result.getName(), result.getSnippet(), result.getSnippetSource()))
|
||||
.collect(toList())));
|
||||
userPromptTextArea.setRequestHandler(requestHandler);
|
||||
userPromptTextArea.setSubmitEnabled(false);
|
||||
requestHandler.call(conversation, message, isRetry);
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +247,7 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
|
||||
private void stopStreaming(ChatMessageResponseBody responseContainer) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
userTextArea.setSubmitEnabled(true);
|
||||
userPromptTextArea.setSubmitEnabled(true);
|
||||
responseContainer.hideCarets();
|
||||
});
|
||||
}
|
||||
|
|
@ -261,15 +293,52 @@ public abstract class BaseChatToolWindowTabPanel implements ChatToolWindowTabPan
|
|||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
|
||||
// JBUI.Panels.simplePanel(8, 0).add();
|
||||
JPanel chatTextAreaWrapper = new JPanel(new BorderLayout());
|
||||
chatTextAreaWrapper.setBorder(JBUI.Borders.compound(
|
||||
|
||||
var model = getModel();
|
||||
var modelIconWrapper = JBUI.Panels.simplePanel(
|
||||
new ModelIconLabel(getClientCode(), model)).withBorder(JBUI.Borders.empty(0, 0, 8, 4));
|
||||
modelIconWrapper.setBackground(getPanelBackgroundColor());
|
||||
|
||||
var wrapper = new JPanel(new BorderLayout());
|
||||
wrapper.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 0, 0),
|
||||
JBUI.Borders.empty(8)));
|
||||
chatTextAreaWrapper.setBackground(getPanelBackgroundColor());
|
||||
chatTextAreaWrapper.add(userTextArea, BorderLayout.SOUTH);
|
||||
rootPanel.add(chatTextAreaWrapper, gbc);
|
||||
userTextArea.requestFocusInWindow();
|
||||
userTextArea.requestFocus();
|
||||
wrapper.setBackground(getPanelBackgroundColor());
|
||||
wrapper.add(userPromptTextArea, BorderLayout.SOUTH);
|
||||
if (model != null) {
|
||||
wrapper.add(modelIconWrapper, BorderLayout.LINE_END);
|
||||
}
|
||||
rootPanel.add(wrapper, gbc);
|
||||
userPromptTextArea.requestFocusInWindow();
|
||||
userPromptTextArea.requestFocus();
|
||||
}
|
||||
|
||||
private String getClientCode() {
|
||||
var settings = SettingsState.getInstance();
|
||||
if (settings.isUseOpenAIService()) {
|
||||
return "chat.completion";
|
||||
}
|
||||
if (settings.isUseAzureService()) {
|
||||
return "azure.chat.completion";
|
||||
}
|
||||
if (settings.isUseYouService()) {
|
||||
return "you.chat.completion";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable String getModel() {
|
||||
var settings = SettingsState.getInstance();
|
||||
if (settings.isUseOpenAIService()) {
|
||||
return OpenAISettingsState.getInstance().getModel();
|
||||
}
|
||||
if (settings.isUseAzureService()) {
|
||||
return AzureSettingsState.getInstance().getModel();
|
||||
}
|
||||
if (settings.isUseYouService()) {
|
||||
return "YouCode";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package ee.carlrobert.codegpt.toolwindow.chat;
|
|||
|
||||
import static ee.carlrobert.codegpt.util.FileUtils.findFileNameExtensionMapping;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||
|
|
@ -11,7 +10,6 @@ import com.intellij.openapi.actionSystem.AnAction;
|
|||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.EditorKind;
|
||||
|
|
@ -21,7 +19,6 @@ import com.intellij.openapi.editor.impl.ContextMenuPopupHandler;
|
|||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
|
|
@ -46,12 +43,10 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
public class ChatToolWindowTabPanelEditor implements Disposable {
|
||||
|
||||
private final Project project;
|
||||
private final Editor editor;
|
||||
private final Map.Entry<String, String> fileNameExtensionMapping;
|
||||
|
||||
public ChatToolWindowTabPanelEditor(Project project, String code, String language, Disposable disposableParent) {
|
||||
this.project = project;
|
||||
this.fileNameExtensionMapping = findFileNameExtensionMapping(language);
|
||||
|
||||
var fileName = "temp_" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now()) + fileNameExtensionMapping.getValue();
|
||||
|
|
@ -60,7 +55,7 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
|
|||
if (document == null) {
|
||||
document = EditorFactory.getInstance().createDocument(code);
|
||||
}
|
||||
disableHighlighting(document);
|
||||
EditorUtils.disableHighlighting(project, document);
|
||||
editor = EditorFactory.getInstance().createEditor(document, project, lightVirtualFile, true, EditorKind.UNTYPED);
|
||||
String originalGroupId = ((EditorEx) editor).getContextMenuGroupId();
|
||||
AnAction originalGroup = originalGroupId == null ? null : ActionManager.getInstance().getAction(originalGroupId);
|
||||
|
|
@ -95,13 +90,6 @@ public class ChatToolWindowTabPanelEditor implements Disposable {
|
|||
return editor;
|
||||
}
|
||||
|
||||
private void disableHighlighting(Document document) {
|
||||
var psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
|
||||
if (psiFile != null) {
|
||||
DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(psiFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
private JPanel createHeaderComponent(String language) {
|
||||
var headerComponent = new JPanel(new BorderLayout());
|
||||
headerComponent.setBorder(JBUI.Borders.compound(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
|
||||
import static java.lang.String.format;
|
||||
|
|
@ -19,12 +19,20 @@ import com.vladsch.flexmark.ast.FencedCodeBlock;
|
|||
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||
import com.vladsch.flexmark.parser.Parser;
|
||||
import com.vladsch.flexmark.util.data.MutableDataSet;
|
||||
import ee.carlrobert.codegpt.completions.SerpResult;
|
||||
import ee.carlrobert.codegpt.settings.SettingsConfigurable;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanelEditor;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ResponseNodeRenderer;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.StreamParser;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.StreamResponseType;
|
||||
import ee.carlrobert.codegpt.util.MarkdownUtils;
|
||||
import ee.carlrobert.codegpt.util.SwingUtils;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextPane;
|
||||
|
|
@ -84,8 +92,10 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
}
|
||||
|
||||
public void displayMissingCredential() {
|
||||
currentlyProcessedTextPane.setText(
|
||||
"<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">API key not provided. Open <a href=\"#\">Settings</a> to set one.</p></html>");
|
||||
var message = SettingsState.getInstance().isUseYouService() ?
|
||||
"Please <a href=\"#\">log in</a> to access the chat feature." :
|
||||
"API key not provided. Open <a href=\"#\">Settings</a> to set one.";
|
||||
currentlyProcessedTextPane.setText(String.format("<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">%s</p></html>", message));
|
||||
currentlyProcessedTextPane.addHyperlinkListener(e -> {
|
||||
if (e.getEventType() == ACTIVATED) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(project, SettingsConfigurable.class);
|
||||
|
|
@ -104,7 +114,6 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void displayError(String message) {
|
||||
var errorText = format("<html><p style=\"margin-top: 4px; margin-bottom: 8px;\">%s</p></html>", message);
|
||||
if (responseReceived) {
|
||||
|
|
@ -120,6 +129,24 @@ public class ChatMessageResponseBody extends JPanel {
|
|||
displayError("Something went wrong.");
|
||||
}
|
||||
|
||||
public void displaySerpResults(List<SerpResult> serpResults) {
|
||||
var titles = serpResults.stream()
|
||||
.map(result -> format("<li style=\"margin-bottom: 4px;\"><a href=\"%s\">%s</a></li>", result.getUrl(), result.getName()))
|
||||
.collect(Collectors.joining());
|
||||
var html = format(
|
||||
"<html>" +
|
||||
"<p><strong>Search results:</strong></p>" +
|
||||
"<ol>%s</ol>" +
|
||||
"</html>", titles);
|
||||
if (responseReceived) {
|
||||
var textPane = createTextPane();
|
||||
textPane.setText(html);
|
||||
add(new ResponseWrapper().add(textPane));
|
||||
} else {
|
||||
currentlyProcessedTextPane.setText(html);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
removeAll();
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ import ee.carlrobert.codegpt.Icons;
|
|||
import ee.carlrobert.codegpt.toolwindow.IconActionButton;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
|
@ -29,7 +30,7 @@ public class ResponsePanel extends JPanel {
|
|||
header = new Header();
|
||||
body = new Body();
|
||||
add(header, BorderLayout.NORTH);
|
||||
add(body, BorderLayout.SOUTH);
|
||||
add(body, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public void enableActions() {
|
||||
|
|
@ -69,7 +70,7 @@ public class ResponsePanel extends JPanel {
|
|||
setBorder(JBUI.Borders.empty(12, 8, 4, 8));
|
||||
add(getIconLabel(), BorderLayout.LINE_START);
|
||||
|
||||
iconsWrapper = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0));
|
||||
iconsWrapper = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
|
||||
iconsWrapper.setBackground(getBackground());
|
||||
add(iconsWrapper, BorderLayout.LINE_END);
|
||||
}
|
||||
|
|
@ -81,7 +82,7 @@ public class ResponsePanel extends JPanel {
|
|||
}
|
||||
|
||||
public void addReloadAction(Runnable onReload) {
|
||||
iconsWrapper.add(new IconActionButton("Reload response", Actions.Refresh, new AnAction() {
|
||||
addIconActionButton(new IconActionButton("Reload response", Actions.Refresh, new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
enableActions(false);
|
||||
|
|
@ -91,7 +92,7 @@ public class ResponsePanel extends JPanel {
|
|||
}
|
||||
|
||||
public void addDeleteAction(Runnable onDelete) {
|
||||
iconsWrapper.add(new IconActionButton("Delete response", Actions.GC, new AnAction() {
|
||||
addIconActionButton(new IconActionButton("Delete response", Actions.GC, new AnAction() {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
onDelete.run();
|
||||
|
|
@ -99,6 +100,13 @@ public class ResponsePanel extends JPanel {
|
|||
}));
|
||||
}
|
||||
|
||||
private void addIconActionButton(IconActionButton iconActionButton) {
|
||||
if (iconsWrapper.getComponents() != null && iconsWrapper.getComponents().length > 0) {
|
||||
iconsWrapper.add(Box.createHorizontalStrut(8));
|
||||
}
|
||||
iconsWrapper.add(iconActionButton);
|
||||
}
|
||||
|
||||
private JBLabel getIconLabel() {
|
||||
return new JBLabel("CodeGPT", Icons.DefaultIcon, SwingConstants.LEADING)
|
||||
.setAllowAutoWrapping(true)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat.components;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
|
|
@ -33,7 +33,7 @@ import javax.swing.event.DocumentListener;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class UserTextArea extends JPanel {
|
||||
public class UserPromptTextArea extends JPanel {
|
||||
|
||||
private static final String TEXT_SUBMIT = "text-submit";
|
||||
private static final String INSERT_BREAK = "insert-break";
|
||||
|
|
@ -47,7 +47,7 @@ public class UserTextArea extends JPanel {
|
|||
private JPanel iconsPanel;
|
||||
private boolean submitEnabled = true;
|
||||
|
||||
public UserTextArea(Consumer<String> onSubmit) {
|
||||
public UserPromptTextArea(Consumer<String> onSubmit) {
|
||||
this.onSubmit = onSubmit;
|
||||
|
||||
textArea = new JBTextArea();
|
||||
|
|
@ -68,12 +68,12 @@ public class UserTextArea extends JPanel {
|
|||
textArea.addFocusListener(new FocusListener() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
UserTextArea.super.paintBorder(UserTextArea.super.getGraphics());
|
||||
UserPromptTextArea.super.paintBorder(UserPromptTextArea.super.getGraphics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
UserTextArea.super.paintBorder(UserTextArea.super.getGraphics());
|
||||
UserPromptTextArea.super.paintBorder(UserPromptTextArea.super.getGraphics());
|
||||
}
|
||||
});
|
||||
textArea.getDocument().addDocumentListener(new DocumentListener() {
|
||||
|
|
@ -139,7 +139,7 @@ public class UserTextArea extends JPanel {
|
|||
}
|
||||
|
||||
private void handleSubmit() {
|
||||
if (submitEnabled && textArea.getText().length() > 0) {
|
||||
if (submitEnabled && !textArea.getText().isEmpty()) {
|
||||
// Replacing each newline with two newlines to ensure proper Markdown formatting
|
||||
var text = textArea.getText().replace("\n", "\n\n");
|
||||
onSubmit.accept(text);
|
||||
|
|
@ -13,13 +13,13 @@ import ee.carlrobert.codegpt.indexes.CodebaseIndexingCompletedNotifier;
|
|||
import ee.carlrobert.codegpt.indexes.CodebaseIndexingTask;
|
||||
import ee.carlrobert.codegpt.indexes.FolderStructureTreePanel;
|
||||
import ee.carlrobert.codegpt.settings.SettingsConfigurable;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.user.UserManager;
|
||||
import ee.carlrobert.codegpt.user.auth.AuthenticationNotifier;
|
||||
import ee.carlrobert.codegpt.user.auth.SignedOutNotifier;
|
||||
import ee.carlrobert.codegpt.util.OverlayUtils;
|
||||
import ee.carlrobert.codegpt.util.SwingUtils;
|
||||
import ee.carlrobert.codegpt.embeddings.VectorStore;
|
||||
import ee.carlrobert.vector.VectorStore;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class ContextualChatToolWindowLandingPanel extends ResponsePanel {
|
|||
var description = createTextPane();
|
||||
var userManager = UserManager.getInstance();
|
||||
|
||||
if (userManager.getSession() == null) {
|
||||
if (userManager.getAuthenticationResponse() == null) {
|
||||
description.setText("<html>" +
|
||||
"<p style=\"margin-top: 4px; margin-bottom: 4px;\">It looks like you haven't logged in. Please <a href=\"LOGIN\">log in</a> to use the feature.</p>" +
|
||||
"</html>");
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ public class ContextualChatToolWindowTabPanel extends BaseChatToolWindowTabPanel
|
|||
public ContextualChatToolWindowTabPanel(@NotNull Project project) {
|
||||
super(project, true);
|
||||
displayLandingView();
|
||||
userTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed());
|
||||
userPromptTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed());
|
||||
|
||||
project.getMessageBus()
|
||||
.connect()
|
||||
.subscribe(CodebaseIndexingCompletedNotifier.INDEXING_COMPLETED_TOPIC,
|
||||
(CodebaseIndexingCompletedNotifier) () -> userTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed()));
|
||||
(CodebaseIndexingCompletedNotifier) () -> userPromptTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed()));
|
||||
|
||||
var messageBusConnection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
messageBusConnection.subscribe(AuthenticationNotifier.AUTHENTICATION_TOPIC,
|
||||
(AuthenticationNotifier) () -> userTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed()));
|
||||
messageBusConnection.subscribe(SignedOutNotifier.SIGNED_OUT_TOPIC, (SignedOutNotifier) () -> userTextArea.setTextAreaEnabled(false));
|
||||
(AuthenticationNotifier) () -> userPromptTextArea.setTextAreaEnabled(UserManager.getInstance().isSubscribed()));
|
||||
messageBusConnection.subscribe(SignedOutNotifier.SIGNED_OUT_TOPIC, (SignedOutNotifier) () -> userPromptTextArea.setTextAreaEnabled(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project;
|
|||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.ui.content.Content;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
|
|
@ -55,6 +56,15 @@ public class StandardChatToolWindowContentManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void displayConversation(Conversation conversation) {
|
||||
displayChatTab();
|
||||
tryFindChatTabbedPane()
|
||||
.ifPresent(tabbedPane -> tabbedPane.tryFindActiveConversationTitle(conversation.getId())
|
||||
.ifPresentOrElse(
|
||||
title -> tabbedPane.setSelectedIndex(tabbedPane.indexOfTab(title)),
|
||||
() -> tabbedPane.addNewTab(new StandardChatToolWindowTabPanel(project, conversation))));
|
||||
}
|
||||
|
||||
public StandardChatToolWindowTabPanel createNewTabPanel() {
|
||||
displayChatTab();
|
||||
var tabbedPane = tryFindChatTabbedPane();
|
||||
|
|
@ -90,12 +100,10 @@ public class StandardChatToolWindowContentManager {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void resetTabbedPane() {
|
||||
public void resetActiveTab() {
|
||||
tryFindChatTabbedPane().ifPresent(tabbedPane -> {
|
||||
tabbedPane.clearAll();
|
||||
var tabPanel = new StandardChatToolWindowTabPanel(project);
|
||||
tabPanel.displayLandingView();
|
||||
tabbedPane.addNewTab(tabPanel);
|
||||
tabbedPane.addNewTab(new StandardChatToolWindowTabPanel(project));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import static javax.swing.event.HyperlinkEvent.EventType.ACTIVATED;
|
|||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.util.SwingUtils;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JTextPane;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package ee.carlrobert.codegpt.toolwindow.chat.standard;
|
|||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionToolbar;
|
||||
import com.intellij.openapi.actionSystem.Constraints;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.DefaultCompactActionGroup;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.SimpleToolWindowPanel;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
|
|
@ -11,6 +13,7 @@ import ee.carlrobert.codegpt.actions.toolwindow.ClearChatWindowAction;
|
|||
import ee.carlrobert.codegpt.actions.toolwindow.CreateNewConversationAction;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import java.awt.FlowLayout;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
||||
|
|
@ -21,27 +24,22 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
}
|
||||
|
||||
private void initialize(Project project, Disposable parentDisposable) {
|
||||
var tabPanel = new StandardChatToolWindowTabPanel(project);
|
||||
var conversation = ConversationsState.getCurrentConversation();
|
||||
if (conversation == null) {
|
||||
tabPanel.displayLandingView();
|
||||
} else {
|
||||
tabPanel.displayConversation(conversation);
|
||||
}
|
||||
|
||||
var tabPanel = new StandardChatToolWindowTabPanel(project, conversation);
|
||||
var tabbedPane = createTabbedPane(tabPanel, parentDisposable);
|
||||
setToolbar(createActionToolbar(project, tabbedPane).getComponent());
|
||||
var toolbarComponent = createActionToolbar(project, tabbedPane).getComponent();
|
||||
toolbarComponent.setLayout(new FlowLayout());
|
||||
|
||||
setToolbar(toolbarComponent);
|
||||
setContent(tabbedPane);
|
||||
|
||||
Disposer.register(parentDisposable, tabPanel);
|
||||
}
|
||||
|
||||
private ActionToolbar createActionToolbar(Project project, StandardChatToolWindowTabbedPane tabbedPane) {
|
||||
var actionGroup = new DefaultActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
var actionGroup = new DefaultCompactActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new CreateNewConversationAction(() -> {
|
||||
var panel = new StandardChatToolWindowTabPanel(project);
|
||||
panel.displayLandingView();
|
||||
tabbedPane.addNewTab(panel);
|
||||
tabbedPane.addNewTab(new StandardChatToolWindowTabPanel(project));
|
||||
repaint();
|
||||
revalidate();
|
||||
}));
|
||||
|
|
@ -50,7 +48,7 @@ public class StandardChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
actionGroup.add(new OpenInEditorAction());
|
||||
|
||||
var toolbar = ActionManager.getInstance()
|
||||
.createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, false);
|
||||
.createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, true);
|
||||
toolbar.setTargetComponent(this);
|
||||
return toolbar;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,20 +6,31 @@ import com.intellij.openapi.editor.impl.EditorImpl;
|
|||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.BaseChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.components.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.util.EditorUtils;
|
||||
import ee.carlrobert.codegpt.util.FileUtils;
|
||||
import ee.carlrobert.codegpt.util.OverlayUtils;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
||||
|
||||
public StandardChatToolWindowTabPanel(@NotNull Project project) {
|
||||
this(project, null);
|
||||
}
|
||||
|
||||
public StandardChatToolWindowTabPanel(@NotNull Project project, @Nullable Conversation conversation) {
|
||||
super(project, false);
|
||||
if (conversation == null) {
|
||||
displayLandingView();
|
||||
} else {
|
||||
displayConversation(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -51,12 +62,20 @@ public class StandardChatToolWindowTabPanel extends BaseChatToolWindowTabPanel {
|
|||
public void displayConversation(@NotNull Conversation conversation) {
|
||||
clearWindow();
|
||||
conversation.getMessages().forEach(message -> {
|
||||
var messageResponseBody = new ChatMessageResponseBody(project, this)
|
||||
.withResponse(message.getResponse());
|
||||
|
||||
var serpResults = message.getSerpResults();
|
||||
if (SettingsState.getInstance().isDisplayWebSearchResults() && serpResults != null && !serpResults.isEmpty()) {
|
||||
messageResponseBody.displaySerpResults(serpResults);
|
||||
}
|
||||
|
||||
var messageWrapper = createNewMessageWrapper(message.getId());
|
||||
messageWrapper.add(new UserMessagePanel(project, message, false, this));
|
||||
messageWrapper.add(new ResponsePanel()
|
||||
.withReloadAction(() -> reloadMessage(message, conversation))
|
||||
.withDeleteAction(() -> deleteMessage(message.getId(), messageWrapper, conversation))
|
||||
.addContent(new ChatMessageResponseBody(project, this).withResponse(message.getResponse())));
|
||||
.addContent(messageResponseBody));
|
||||
});
|
||||
setConversation(conversation);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.intellij.ui.components.JBLabel;
|
|||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.state.ModelSettingsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
|
@ -36,7 +36,6 @@ public class StandardChatToolWindowTabbedPane extends JBTabbedPane {
|
|||
this.parentDisposable = parentDisposable;
|
||||
setTabComponentInsets(null);
|
||||
setComponentPopupMenu(new TabPopupMenu());
|
||||
|
||||
addChangeListener(e -> refreshTabState());
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +103,7 @@ public class StandardChatToolWindowTabbedPane extends JBTabbedPane {
|
|||
var conversation = toolWindowPanel.getConversation();
|
||||
if (conversation != null) {
|
||||
ConversationsState.getInstance().setCurrentConversation(conversation);
|
||||
ModelSettingsState.getInstance().sync(conversation);
|
||||
SettingsState.getInstance().sync(conversation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,94 +1,111 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.conversations;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.justifyLeft;
|
||||
import static ee.carlrobert.codegpt.util.ThemeUtils.getPanelBackgroundColor;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.JBFont;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.DeleteConversationAction;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.state.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.IconActionButton;
|
||||
import ee.carlrobert.codegpt.toolwindow.ModelIconLabel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Font;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class ConversationPanel extends JPanel {
|
||||
|
||||
private final Conversation conversation;
|
||||
|
||||
ConversationPanel(Conversation conversation, boolean isSelected) {
|
||||
this.conversation = conversation;
|
||||
addStyles(isSelected);
|
||||
|
||||
var constraints = new GridBagConstraints();
|
||||
constraints.insets = JBUI.insets(0, 10);
|
||||
addChatIcon(constraints);
|
||||
addTextPanel(constraints);
|
||||
ConversationPanel(@NotNull Project project, @NotNull Conversation conversation, @NotNull Runnable onDelete) {
|
||||
super(new BorderLayout());
|
||||
setBackground(JBColor.background());
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
SettingsState.getInstance().sync(conversation);
|
||||
StandardChatToolWindowContentManager.getInstance(project).displayConversation(conversation);
|
||||
}
|
||||
});
|
||||
addStyles(isSelected(conversation));
|
||||
addTextPanel(conversation, onDelete);
|
||||
setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
}
|
||||
|
||||
private boolean isSelected(Conversation conversation) {
|
||||
var currentConversation = ConversationsState.getCurrentConversation();
|
||||
return currentConversation != null && currentConversation.getId().equals(conversation.getId());
|
||||
}
|
||||
|
||||
private void addStyles(boolean isSelected) {
|
||||
setBackground(JBColor.background().darker());
|
||||
if (isSelected) {
|
||||
setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createMatteBorder(4, 4, 4, 4, JBColor.green),
|
||||
JBUI.Borders.empty(10)));
|
||||
} else {
|
||||
setBorder(JBUI.Borders.empty(10));
|
||||
}
|
||||
var border = isSelected ?
|
||||
JBUI.Borders.customLine(JBUI.CurrentTheme.ActionButton.focusedBorder(), 2, 2, 2, 2) :
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 1, 0);
|
||||
setBackground(getPanelBackgroundColor());
|
||||
setBorder(JBUI.Borders.compound(border, JBUI.Borders.empty(8)));
|
||||
setLayout(new GridBagLayout());
|
||||
setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
}
|
||||
|
||||
private void addChatIcon(GridBagConstraints constraints) {
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
constraints.weightx = 0.0;
|
||||
constraints.fill = GridBagConstraints.NONE;
|
||||
add(new JLabel(AllIcons.Actions.Annotate), constraints);
|
||||
}
|
||||
|
||||
private void addTextPanel(GridBagConstraints constraints) {
|
||||
private void addTextPanel(Conversation conversation, Runnable onDelete) {
|
||||
var constraints = new GridBagConstraints();
|
||||
constraints.gridx = 1;
|
||||
constraints.weightx = 1.0;
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
add(createTextPanel(), constraints);
|
||||
add(createTextPanel(conversation, onDelete), constraints);
|
||||
}
|
||||
|
||||
private JPanel createTextPanel() {
|
||||
var title = new JLabel(getFirstPrompt());
|
||||
title.setBorder(JBUI.Borders.emptyBottom(8));
|
||||
title.setFont(title.getFont().deriveFont(title.getFont().getStyle() | Font.BOLD));
|
||||
private JPanel createTextPanel(Conversation conversation, Runnable onDelete) {
|
||||
var headerPanel = new JPanel(new GridBagLayout());
|
||||
headerPanel.setBorder(JBUI.Borders.emptyBottom(12));
|
||||
|
||||
var textPanel = new JPanel();
|
||||
textPanel.setBackground(getBackground());
|
||||
textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.PAGE_AXIS));
|
||||
textPanel.add(justifyLeft(title));
|
||||
var gbc = new GridBagConstraints();
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.weightx = 1.0;
|
||||
gbc.gridx = 0;
|
||||
|
||||
var bottomPanel = new JPanel();
|
||||
bottomPanel.setBackground(getBackground());
|
||||
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
|
||||
headerPanel.setBackground(getPanelBackgroundColor());
|
||||
headerPanel.add(new JBLabel(getFirstPrompt(conversation))
|
||||
.withFont(JBFont.label().asBold()), gbc);
|
||||
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 0;
|
||||
headerPanel.add(new IconActionButton("Delete conversation", AllIcons.Actions.GC, new DeleteConversationAction(onDelete)), gbc);
|
||||
|
||||
var bottomPanel = new JPanel(new BorderLayout());
|
||||
bottomPanel.setBackground(getPanelBackgroundColor());
|
||||
bottomPanel.add(new JLabel(conversation.getUpdatedOn()
|
||||
.format(DateTimeFormatter.ofPattern("M/d/yyyy, h:mm:ss a"))));
|
||||
bottomPanel.add(Box.createHorizontalGlue());
|
||||
.format(DateTimeFormatter.ofPattern("M/d/yyyy, h:mm:ss a"))), BorderLayout.WEST);
|
||||
if (conversation.getModel() != null) {
|
||||
bottomPanel.add(new JLabel(conversation.getModel()));
|
||||
bottomPanel.add(new ModelIconLabel(conversation.getClientCode(), conversation.getModel()), BorderLayout.EAST);
|
||||
}
|
||||
textPanel.add(bottomPanel);
|
||||
|
||||
var textPanel = new JPanel(new BorderLayout());
|
||||
textPanel.setBackground(getPanelBackgroundColor());
|
||||
textPanel.add(headerPanel, BorderLayout.NORTH);
|
||||
textPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
return textPanel;
|
||||
}
|
||||
|
||||
private String getFirstPrompt() {
|
||||
private String getFirstPrompt(Conversation conversation) {
|
||||
var messages = conversation.getMessages();
|
||||
var prompt = "";
|
||||
if (!messages.isEmpty()) {
|
||||
prompt = conversation.getMessages().get(0).getPrompt();
|
||||
if (messages.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return prompt;
|
||||
return messages.get(0).getPrompt();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="ee.carlrobert.codegpt.toolwindow.conversations.ConversationsToolWindow">
|
||||
<grid id="27dc6" binding="conversationsToolWindowContent" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<scrollpane id="77046" binding="scrollPane" custom-create="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</scrollpane>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
|
@ -9,15 +9,10 @@ import com.intellij.ui.components.JBScrollPane;
|
|||
import com.intellij.util.ui.JBFont;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.DeleteAllConversationsAction;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.DeleteConversationAction;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.MoveDownAction;
|
||||
import ee.carlrobert.codegpt.actions.toolwindow.MoveUpAction;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.state.ModelSettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowTabPanel;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
|
@ -25,29 +20,35 @@ import javax.swing.JScrollPane;
|
|||
import javax.swing.ScrollPaneConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConversationsToolWindow {
|
||||
public class ConversationsToolWindow extends JPanel {
|
||||
|
||||
private final Project project;
|
||||
private final ConversationService conversationService;
|
||||
private JPanel conversationsToolWindowContent;
|
||||
private JScrollPane scrollPane;
|
||||
private ScrollablePanel scrollablePanel;
|
||||
private final ScrollablePanel scrollablePanel;
|
||||
private final JScrollPane scrollPane;
|
||||
|
||||
public ConversationsToolWindow(@NotNull Project project) {
|
||||
this.project = project;
|
||||
this.conversationService = ConversationService.getInstance();
|
||||
scrollablePanel = new ScrollablePanel();
|
||||
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
|
||||
|
||||
scrollPane = new JBScrollPane();
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.setViewportView(scrollablePanel);
|
||||
scrollPane.setBorder(null);
|
||||
scrollPane.setViewportBorder(null);
|
||||
refresh();
|
||||
}
|
||||
|
||||
public JPanel getContent() {
|
||||
SimpleToolWindowPanel panel = new SimpleToolWindowPanel(true);
|
||||
panel.setContent(conversationsToolWindowContent);
|
||||
panel.setContent(scrollPane);
|
||||
|
||||
var actionGroup = new DefaultActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new MoveDownAction(this::refresh));
|
||||
actionGroup.add(new MoveUpAction(this::refresh));
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(new DeleteConversationAction(this::refresh));
|
||||
actionGroup.add(new DeleteAllConversationsAction(this::refresh));
|
||||
|
||||
var toolbar = ActionManager.getInstance()
|
||||
|
|
@ -67,46 +68,13 @@ public class ConversationsToolWindow {
|
|||
emptyLabel.setBorder(JBUI.Borders.empty(8));
|
||||
scrollablePanel.add(emptyLabel);
|
||||
} else {
|
||||
sortedConversations.forEach(this::addContent);
|
||||
sortedConversations.forEach(conversation -> {
|
||||
scrollablePanel.add(Box.createVerticalStrut(8));
|
||||
scrollablePanel.add(new ConversationPanel(project, conversation, this::refresh));
|
||||
});
|
||||
}
|
||||
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
private void addContent(Conversation conversation) {
|
||||
var mainPanel = new RootConversationPanel(() -> {
|
||||
ModelSettingsState.getInstance().sync(conversation);
|
||||
|
||||
var toolWindowContentManager = StandardChatToolWindowContentManager.getInstance(project);
|
||||
toolWindowContentManager.displayChatTab();
|
||||
toolWindowContentManager.tryFindChatTabbedPane()
|
||||
.ifPresent(tabbedPane -> tabbedPane.tryFindActiveConversationTitle(conversation.getId())
|
||||
.ifPresentOrElse(
|
||||
title -> tabbedPane.setSelectedIndex(tabbedPane.indexOfTab(title)),
|
||||
() -> {
|
||||
var panel = new StandardChatToolWindowTabPanel(project);
|
||||
panel.displayConversation(conversation);
|
||||
tabbedPane.addNewTab(panel);
|
||||
}));
|
||||
});
|
||||
|
||||
var currentConversation = ConversationsState.getCurrentConversation();
|
||||
var isSelected =
|
||||
currentConversation != null && currentConversation.getId().equals(conversation.getId());
|
||||
mainPanel.add(new ConversationPanel(conversation, isSelected));
|
||||
mainPanel.setBackground(conversationsToolWindowContent.getBackground());
|
||||
scrollablePanel.add(mainPanel);
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
scrollablePanel = new ScrollablePanel();
|
||||
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
|
||||
|
||||
scrollPane = new JBScrollPane();
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.setViewportView(scrollablePanel);
|
||||
scrollPane.setBorder(null);
|
||||
scrollPane.setViewportBorder(null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.conversations;
|
||||
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
class RootConversationPanel extends JPanel {
|
||||
|
||||
RootConversationPanel(Runnable onClick) {
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
setBorder(JBUI.Borders.empty(10, 20));
|
||||
setBackground(JBColor.background());
|
||||
addMouseListener(getMouseListener(onClick));
|
||||
}
|
||||
|
||||
private MouseListener getMouseListener(Runnable onClick) {
|
||||
return new MouseListener() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent mouseEvent) {
|
||||
onClick.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent mouseEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue