mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-07-01 02:29:13 -04:00
fix: Disable shown agent without selecting
This commit is contained in:
@@ -92,7 +92,10 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
m_path->setPalette(pp);
|
m_path->setPalette(pp);
|
||||||
|
|
||||||
m_openBtn = new QPushButton(tr("Open in editor"), this);
|
m_openBtn = new QPushButton(tr("Open in editor"), this);
|
||||||
m_dupBtn = new QPushButton(tr("Duplicate…"), this);
|
m_dupBtn = new QPushButton(tr("Customize a copy…"), this);
|
||||||
|
m_dupBtn->setToolTip(
|
||||||
|
tr("Create an editable user agent that inherits from this one — "
|
||||||
|
"override only the fields you want."));
|
||||||
m_deleteBtn = new QPushButton(tr("Delete"), this);
|
m_deleteBtn = new QPushButton(tr("Delete"), this);
|
||||||
connect(m_openBtn, &QPushButton::clicked, this, [this] {
|
connect(m_openBtn, &QPushButton::clicked, this, [this] {
|
||||||
if (m_current)
|
if (m_current)
|
||||||
@@ -107,7 +110,8 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
emit deleteRequested(*m_current);
|
emit deleteRequested(*m_current);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto *actions = new QHBoxLayout;
|
m_actionsHolder = new QWidget(this);
|
||||||
|
auto *actions = new QHBoxLayout(m_actionsHolder);
|
||||||
actions->setContentsMargins(0, 0, 0, 0);
|
actions->setContentsMargins(0, 0, 0, 0);
|
||||||
actions->setSpacing(6);
|
actions->setSpacing(6);
|
||||||
actions->addWidget(m_openBtn);
|
actions->addWidget(m_openBtn);
|
||||||
@@ -130,11 +134,11 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
headerRow->setContentsMargins(0, 0, 0, 0);
|
headerRow->setContentsMargins(0, 0, 0, 0);
|
||||||
headerRow->setSpacing(8);
|
headerRow->setSpacing(8);
|
||||||
headerRow->addLayout(headerLeft, 1);
|
headerRow->addLayout(headerLeft, 1);
|
||||||
headerRow->addLayout(actions);
|
headerRow->addWidget(m_actionsHolder);
|
||||||
|
|
||||||
auto *headerSep = new QFrame(this);
|
m_headerSep = new QFrame(this);
|
||||||
headerSep->setFrameShape(QFrame::HLine);
|
m_headerSep->setFrameShape(QFrame::HLine);
|
||||||
headerSep->setFrameShadow(QFrame::Sunken);
|
m_headerSep->setFrameShadow(QFrame::Sunken);
|
||||||
|
|
||||||
m_description = new QLabel(this);
|
m_description = new QLabel(this);
|
||||||
m_description->setWordWrap(true);
|
m_description->setWordWrap(true);
|
||||||
@@ -319,18 +323,41 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
m_rawToggle->setText(on ? tr("▾ Hide raw TOML") : tr("▸ Show raw TOML"));
|
m_rawToggle->setText(on ? tr("▾ Hide raw TOML") : tr("▸ Show raw TOML"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_baseRawToggle = new QToolButton(this);
|
||||||
|
m_baseRawToggle->setText(tr("▸ Show base agent TOML"));
|
||||||
|
m_baseRawToggle->setCursor(Qt::PointingHandCursor);
|
||||||
|
m_baseRawToggle->setAutoRaise(true);
|
||||||
|
m_baseRawToggle->setCheckable(true);
|
||||||
|
m_baseRawToml = new QPlainTextEdit(this);
|
||||||
|
m_baseRawToml->setReadOnly(true);
|
||||||
|
m_baseRawToml->setFont(monospaceFont(11));
|
||||||
|
m_baseRawToml->setMinimumHeight(140);
|
||||||
|
m_baseRawToml->setVisible(false);
|
||||||
|
connect(m_baseRawToggle, &QToolButton::toggled, this, [this](bool on) {
|
||||||
|
m_baseRawToml->setVisible(on);
|
||||||
|
m_baseRawToggle->setText(on ? tr("▾ Hide base agent TOML") : tr("▸ Show base agent TOML"));
|
||||||
|
});
|
||||||
|
|
||||||
|
m_body = new QWidget(this);
|
||||||
|
auto *bodyLayout = new QVBoxLayout(m_body);
|
||||||
|
bodyLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
bodyLayout->setSpacing(10);
|
||||||
|
bodyLayout->addWidget(identity);
|
||||||
|
bodyLayout->addWidget(connection);
|
||||||
|
bodyLayout->addWidget(capabilities);
|
||||||
|
bodyLayout->addWidget(match);
|
||||||
|
bodyLayout->addWidget(m_rawToggle, 0, Qt::AlignLeft);
|
||||||
|
bodyLayout->addWidget(m_rawToml);
|
||||||
|
bodyLayout->addWidget(m_baseRawToggle, 0, Qt::AlignLeft);
|
||||||
|
bodyLayout->addWidget(m_baseRawToml);
|
||||||
|
|
||||||
auto *root = new QVBoxLayout(this);
|
auto *root = new QVBoxLayout(this);
|
||||||
root->setContentsMargins(12, 12, 12, 12);
|
root->setContentsMargins(12, 12, 12, 12);
|
||||||
root->setSpacing(10);
|
root->setSpacing(10);
|
||||||
root->addLayout(headerRow);
|
root->addLayout(headerRow);
|
||||||
root->addWidget(headerSep);
|
root->addWidget(m_headerSep);
|
||||||
root->addWidget(m_description);
|
root->addWidget(m_description);
|
||||||
root->addWidget(identity);
|
root->addWidget(m_body);
|
||||||
root->addWidget(connection);
|
|
||||||
root->addWidget(capabilities);
|
|
||||||
root->addWidget(match);
|
|
||||||
root->addWidget(m_rawToggle, 0, Qt::AlignLeft);
|
|
||||||
root->addWidget(m_rawToml);
|
|
||||||
root->addStretch(1);
|
root->addStretch(1);
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
@@ -494,6 +521,8 @@ void AgentDetailPane::setAgent(const AgentConfig &cfg)
|
|||||||
m_current = &m_currentStorage;
|
m_current = &m_currentStorage;
|
||||||
const bool user = cfg.isUserSource();
|
const bool user = cfg.isUserSource();
|
||||||
|
|
||||||
|
setDetailsVisible(true);
|
||||||
|
|
||||||
m_name->setText(cfg.name);
|
m_name->setText(cfg.name);
|
||||||
m_path->setText(cfg.sourcePath);
|
m_path->setText(cfg.sourcePath);
|
||||||
m_description->setText(
|
m_description->setText(
|
||||||
@@ -576,23 +605,17 @@ void AgentDetailPane::setAgent(const AgentConfig &cfg)
|
|||||||
m_filePatternsValue->setText(cfg.match.filePatterns.join(QStringLiteral(", ")));
|
m_filePatternsValue->setText(cfg.match.filePatterns.join(QStringLiteral(", ")));
|
||||||
m_filePatternsValue->setPlaceholderText(tr("(matches every file)"));
|
m_filePatternsValue->setPlaceholderText(tr("(matches every file)"));
|
||||||
|
|
||||||
const FileReadResult raw = readFileTextCapped(cfg.sourcePath, kRawTomlMaxBytes);
|
fillRawToml(m_rawToml, cfg.sourcePath);
|
||||||
switch (raw.status) {
|
|
||||||
case FileReadStatus::Ok:
|
const QString basePath
|
||||||
m_rawToml->setPlainText(raw.content);
|
= m_agentFactory ? m_agentFactory->sourcePathForName(cfg.extendsName) : QString();
|
||||||
break;
|
const bool hasBase = !cfg.extendsName.isEmpty() && !basePath.isEmpty();
|
||||||
case FileReadStatus::Truncated:
|
m_baseRawToggle->setVisible(hasBase);
|
||||||
m_rawToml->setPlainText(
|
m_baseRawToml->setVisible(hasBase && m_baseRawToggle->isChecked());
|
||||||
raw.content + QStringLiteral("\n\n")
|
if (hasBase)
|
||||||
+ tr("(truncated at %1 bytes)").arg(kRawTomlMaxBytes));
|
fillRawToml(m_baseRawToml, basePath);
|
||||||
break;
|
else
|
||||||
case FileReadStatus::Empty:
|
m_baseRawToml->clear();
|
||||||
m_rawToml->setPlainText(tr("(source file is empty)"));
|
|
||||||
break;
|
|
||||||
case FileReadStatus::OpenFailed:
|
|
||||||
m_rawToml->setPlainText(tr("(source file unavailable: %1)").arg(raw.error));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_openBtn->setEnabled(user);
|
m_openBtn->setEnabled(user);
|
||||||
m_openBtn->setToolTip(
|
m_openBtn->setToolTip(
|
||||||
@@ -609,6 +632,7 @@ void AgentDetailPane::clear()
|
|||||||
{
|
{
|
||||||
m_currentStorage = AgentConfig{};
|
m_currentStorage = AgentConfig{};
|
||||||
m_current = nullptr;
|
m_current = nullptr;
|
||||||
|
setDetailsVisible(false);
|
||||||
m_name->setText(tr("Select an agent"));
|
m_name->setText(tr("Select an agent"));
|
||||||
m_path->clear();
|
m_path->clear();
|
||||||
m_description->setText(tr("Pick an agent from the list to see its details."));
|
m_description->setText(tr("Pick an agent from the list to see its details."));
|
||||||
@@ -638,6 +662,9 @@ void AgentDetailPane::clear()
|
|||||||
m_toolsResetBtn->setVisible(false);
|
m_toolsResetBtn->setVisible(false);
|
||||||
m_filePatternsValue->clear();
|
m_filePatternsValue->clear();
|
||||||
m_rawToml->clear();
|
m_rawToml->clear();
|
||||||
|
m_baseRawToml->clear();
|
||||||
|
m_baseRawToggle->setVisible(false);
|
||||||
|
m_baseRawToml->setVisible(false);
|
||||||
m_openBtn->setEnabled(false);
|
m_openBtn->setEnabled(false);
|
||||||
m_dupBtn->setEnabled(false);
|
m_dupBtn->setEnabled(false);
|
||||||
m_deleteBtn->setEnabled(false);
|
m_deleteBtn->setEnabled(false);
|
||||||
@@ -661,6 +688,35 @@ QLineEdit *AgentDetailPane::makeReadOnlyLine(bool mono)
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AgentDetailPane::fillRawToml(QPlainTextEdit *view, const QString &path)
|
||||||
|
{
|
||||||
|
const FileReadResult raw = readFileTextCapped(path, kRawTomlMaxBytes);
|
||||||
|
switch (raw.status) {
|
||||||
|
case FileReadStatus::Ok:
|
||||||
|
view->setPlainText(raw.content);
|
||||||
|
break;
|
||||||
|
case FileReadStatus::Truncated:
|
||||||
|
view->setPlainText(
|
||||||
|
raw.content + QStringLiteral("\n\n")
|
||||||
|
+ tr("(truncated at %1 bytes)").arg(kRawTomlMaxBytes));
|
||||||
|
break;
|
||||||
|
case FileReadStatus::Empty:
|
||||||
|
view->setPlainText(tr("(source file is empty)"));
|
||||||
|
break;
|
||||||
|
case FileReadStatus::OpenFailed:
|
||||||
|
view->setPlainText(tr("(source file unavailable: %1)").arg(raw.error));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentDetailPane::setDetailsVisible(bool visible)
|
||||||
|
{
|
||||||
|
m_headerSep->setVisible(visible);
|
||||||
|
m_path->setVisible(visible);
|
||||||
|
m_actionsHolder->setVisible(visible);
|
||||||
|
m_body->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
void AgentDetailPane::applyCodePalette()
|
void AgentDetailPane::applyCodePalette()
|
||||||
{
|
{
|
||||||
QScopedValueRollback<bool> guard(m_inApplyPalette, true);
|
QScopedValueRollback<bool> guard(m_inApplyPalette, true);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
class QFrame;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QPlainTextEdit;
|
class QPlainTextEdit;
|
||||||
@@ -51,6 +52,8 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QLineEdit *makeReadOnlyLine(bool mono = false);
|
QLineEdit *makeReadOnlyLine(bool mono = false);
|
||||||
|
void fillRawToml(QPlainTextEdit *view, const QString &path);
|
||||||
|
void setDetailsVisible(bool visible);
|
||||||
void applyCodePalette();
|
void applyCodePalette();
|
||||||
void populateProviderCombo();
|
void populateProviderCombo();
|
||||||
void onChangeModel();
|
void onChangeModel();
|
||||||
@@ -69,6 +72,9 @@ private:
|
|||||||
|
|
||||||
QLabel *m_name = nullptr;
|
QLabel *m_name = nullptr;
|
||||||
QLabel *m_path = nullptr;
|
QLabel *m_path = nullptr;
|
||||||
|
QFrame *m_headerSep = nullptr;
|
||||||
|
QWidget *m_actionsHolder = nullptr;
|
||||||
|
QWidget *m_body = nullptr;
|
||||||
QPushButton *m_openBtn = nullptr;
|
QPushButton *m_openBtn = nullptr;
|
||||||
QPushButton *m_dupBtn = nullptr;
|
QPushButton *m_dupBtn = nullptr;
|
||||||
QPushButton *m_deleteBtn = nullptr;
|
QPushButton *m_deleteBtn = nullptr;
|
||||||
@@ -99,6 +105,9 @@ private:
|
|||||||
|
|
||||||
QToolButton *m_rawToggle = nullptr;
|
QToolButton *m_rawToggle = nullptr;
|
||||||
QPlainTextEdit *m_rawToml = nullptr;
|
QPlainTextEdit *m_rawToml = nullptr;
|
||||||
|
|
||||||
|
QToolButton *m_baseRawToggle = nullptr;
|
||||||
|
QPlainTextEdit *m_baseRawToml = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Settings
|
} // namespace QodeAssist::Settings
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ private:
|
|||||||
this,
|
this,
|
||||||
tr("Open agent"),
|
tr("Open agent"),
|
||||||
tr("'%1' is bundled with the plugin and read-only.\n"
|
tr("'%1' is bundled with the plugin and read-only.\n"
|
||||||
"Use Duplicate to create an editable user copy.")
|
"Use Customize a copy… to create an editable user agent.")
|
||||||
.arg(name));
|
.arg(name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ private:
|
|||||||
{
|
{
|
||||||
const AgentDuplicateResult res = duplicateAgentInUserDir(parent, *m_agentFactory);
|
const AgentDuplicateResult res = duplicateAgentInUserDir(parent, *m_agentFactory);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
QMessageBox::warning(this, tr("Duplicate"), res.error);
|
QMessageBox::warning(this, tr("Customize a copy"), res.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QString newName = res.newName;
|
const QString newName = res.newName;
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ void AgentFactory::reload()
|
|||||||
|
|
||||||
QDir().mkpath(userAgentsDir());
|
QDir().mkpath(userAgentsDir());
|
||||||
auto result = Agents::AgentLoader::load(agentQrcPrefix(), userAgentsDir());
|
auto result = Agents::AgentLoader::load(agentQrcPrefix(), userAgentsDir());
|
||||||
|
m_sourcePathByName = std::move(result.sourcePathByName);
|
||||||
for (const QString &err : result.errors)
|
for (const QString &err : result.errors)
|
||||||
LOG_MESSAGE(QString("[Agents] error: %1").arg(err));
|
LOG_MESSAGE(QString("[Agents] error: %1").arg(err));
|
||||||
for (const QString &warn : result.warnings)
|
for (const QString &warn : result.warnings)
|
||||||
@@ -212,6 +213,11 @@ const AgentConfig *AgentFactory::configByName(const QString &name) const
|
|||||||
return &m_configs[it.value()];
|
return &m_configs[it.value()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AgentFactory::sourcePathForName(const QString &name) const
|
||||||
|
{
|
||||||
|
return m_sourcePathByName.value(name);
|
||||||
|
}
|
||||||
|
|
||||||
QStringList AgentFactory::configNames() const
|
QStringList AgentFactory::configNames() const
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
@@ -323,6 +329,7 @@ void AgentFactory::clear()
|
|||||||
Q_ASSERT(thread() == QThread::currentThread());
|
Q_ASSERT(thread() == QThread::currentThread());
|
||||||
m_configs.clear();
|
m_configs.clear();
|
||||||
m_indexByName.clear();
|
m_indexByName.clear();
|
||||||
|
m_sourcePathByName.clear();
|
||||||
m_baseModelByName.clear();
|
m_baseModelByName.clear();
|
||||||
m_baseProviderByName.clear();
|
m_baseProviderByName.clear();
|
||||||
m_baseToolsByName.clear();
|
m_baseToolsByName.clear();
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public:
|
|||||||
[[nodiscard]] static QString userConfigDir();
|
[[nodiscard]] static QString userConfigDir();
|
||||||
|
|
||||||
[[nodiscard]] const AgentConfig *configByName(const QString &name) const;
|
[[nodiscard]] const AgentConfig *configByName(const QString &name) const;
|
||||||
|
[[nodiscard]] QString sourcePathForName(const QString &name) const;
|
||||||
[[nodiscard]] QStringList configNames() const;
|
[[nodiscard]] QStringList configNames() const;
|
||||||
[[nodiscard]] const std::vector<AgentConfig> &configs() const noexcept { return m_configs; }
|
[[nodiscard]] const std::vector<AgentConfig> &configs() const noexcept { return m_configs; }
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
std::vector<AgentConfig> m_configs;
|
std::vector<AgentConfig> m_configs;
|
||||||
QHash<QString, qsizetype> m_indexByName;
|
QHash<QString, qsizetype> m_indexByName;
|
||||||
|
QHash<QString, QString> m_sourcePathByName;
|
||||||
QHash<QString, QString> m_baseModelByName;
|
QHash<QString, QString> m_baseModelByName;
|
||||||
QHash<QString, QString> m_baseProviderByName;
|
QHash<QString, QString> m_baseProviderByName;
|
||||||
QHash<QString, bool> m_baseToolsByName;
|
QHash<QString, bool> m_baseToolsByName;
|
||||||
|
|||||||
@@ -348,6 +348,9 @@ AgentLoader::LoadResult AgentLoader::load(const QString &qrcPrefix, const QStrin
|
|||||||
scanDir(qrcPrefix, /*isUserLayer=*/false, raw, result.errors, &result.warnings);
|
scanDir(qrcPrefix, /*isUserLayer=*/false, raw, result.errors, &result.warnings);
|
||||||
scanDir(userDir, /*isUserLayer=*/true, raw, result.errors, &result.warnings);
|
scanDir(userDir, /*isUserLayer=*/true, raw, result.errors, &result.warnings);
|
||||||
|
|
||||||
|
for (auto it = raw.constBegin(); it != raw.constEnd(); ++it)
|
||||||
|
result.sourcePathByName.insert(it.key(), it.value().filePath);
|
||||||
|
|
||||||
for (auto it = raw.constBegin(); it != raw.constEnd(); ++it) {
|
for (auto it = raw.constBegin(); it != raw.constEnd(); ++it) {
|
||||||
const QString &name = it.key();
|
const QString &name = it.key();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -18,6 +19,7 @@ public:
|
|||||||
struct LoadResult
|
struct LoadResult
|
||||||
{
|
{
|
||||||
std::vector<AgentConfig> configs;
|
std::vector<AgentConfig> configs;
|
||||||
|
QHash<QString, QString> sourcePathByName;
|
||||||
QStringList errors;
|
QStringList errors;
|
||||||
QStringList warnings;
|
QStringList warnings;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user