refactor: Provider settings panel improve

This commit is contained in:
Petr Mironychev
2026-06-29 10:42:33 +02:00
parent 70c6d30a72
commit 86c537477d
16 changed files with 49 additions and 22 deletions

View File

@@ -42,6 +42,11 @@ ProviderDetailPane::ProviderDetailPane(QWidget *parent)
spp.setColor(QPalette::WindowText, Utils::creatorColor(Utils::Theme::PanelTextColorMid));
m_sourcePathLabel->setPalette(spp);
m_protocolLabel = new QLabel(this);
m_protocolLabel->setPalette(spp);
m_protocolLabel->setToolTip(
tr("The client API (protocol) this provider speaks. Fixed when the provider is created."));
m_editBtn = new QPushButton(tr("Edit…"), this);
m_editBtn->setDefault(true);
m_openInEditorBtn = new QPushButton(tr("Open in editor"), this);
@@ -89,6 +94,7 @@ ProviderDetailPane::ProviderDetailPane(QWidget *parent)
headerLeft->setContentsMargins(0, 0, 0, 0);
headerLeft->setSpacing(2);
headerLeft->addLayout(titleRow);
headerLeft->addWidget(m_protocolLabel);
headerLeft->addWidget(m_sourcePathLabel);
auto *headerRow = new QHBoxLayout;
@@ -107,8 +113,6 @@ ProviderDetailPane::ProviderDetailPane(QWidget *parent)
auto *identitySection = new SectionBox(tr("Identity"), this);
m_nameEdit = new QLineEdit(this);
m_typeEdit = new QLineEdit(this);
m_typeEdit->setReadOnly(true);
m_descriptionEdit = new QPlainTextEdit(this);
m_descriptionEdit->setMaximumHeight(60);
m_descriptionEdit->setReadOnly(true);
@@ -118,9 +122,6 @@ ProviderDetailPane::ProviderDetailPane(QWidget *parent)
identityGrid->setVerticalSpacing(4);
FormBuilder(identityGrid)
.row(tr("Name:"), m_nameEdit)
.row(tr("Client API:"), m_typeEdit,
tr("The client API this provider speaks. "
"Cannot be changed after creation."))
.row(tr("Description:"), m_descriptionEdit);
identitySection->bodyLayout()->addLayout(identityGrid);
@@ -151,8 +152,10 @@ ProviderDetailPane::ProviderDetailPane(QWidget *parent)
m_revealKeyBtn = new QToolButton(this);
m_revealKeyBtn->setText(QStringLiteral("👁"));
m_revealKeyBtn->setCheckable(true);
m_revealKeyBtn->setToolTip(tr("Show / hide API key"));
m_revealKeyBtn->setToolTip(tr("Show / hide the API key (loads the stored key)"));
connect(m_revealKeyBtn, &QToolButton::toggled, this, [this](bool on) {
if (on && m_apiKeyEdit->text().isEmpty() && m_currentHasStoredKey)
emit apiKeyRevealRequested();
m_apiKeyEdit->setEchoMode(on ? QLineEdit::Normal : QLineEdit::Password);
});
m_apiKeySaveBtn = new QPushButton(tr("Save key"), this);
@@ -307,7 +310,7 @@ void ProviderDetailPane::populate(const Providers::ProviderInstance &inst, bool
inst.description.isEmpty() ? tr("No description provided.") : inst.description);
m_nameEdit->setText(inst.name);
m_typeEdit->setText(inst.clientApi);
m_protocolLabel->setText(tr("via %1").arg(inst.clientApi));
m_descriptionEdit->setPlainText(inst.description);
m_urlEdit->setText(inst.url);
@@ -363,7 +366,7 @@ void ProviderDetailPane::clear()
m_sourcePathLabel->clear();
m_descriptionLabel->clear();
m_nameEdit->clear();
m_typeEdit->clear();
m_protocolLabel->clear();
m_descriptionEdit->clear();
m_urlEdit->clear();
m_apiKeyEdit->clear();
@@ -476,6 +479,16 @@ void ProviderDetailPane::changeEvent(QEvent *event)
}
}
void ProviderDetailPane::showRevealedKey(const QString &key)
{
if (key.isEmpty())
return;
m_apiKeyEdit->setText(key);
m_apiKeyEdit->setEchoMode(QLineEdit::Normal);
if (!m_revealKeyBtn->isChecked())
m_revealKeyBtn->setChecked(true);
}
void ProviderDetailPane::setEditing(bool on)
{
m_editing = on;

View File

@@ -32,6 +32,7 @@ public:
void populate(const Providers::ProviderInstance &inst, bool hasStoredKey);
void clear();
void refreshKeyStatus(bool hasStoredKey);
void showRevealedKey(const QString &key);
void setLaunchState(Providers::ProviderLauncher::State st, const QString &lastError);
void resetLaunchTerminal(const QByteArray &scrollback);
void appendLaunchBytes(const QByteArray &chunk);
@@ -44,6 +45,7 @@ signals:
void deleteRequested();
void apiKeySaveRequested(const QString &newKey);
void apiKeyClearRequested();
void apiKeyRevealRequested();
void launchStartRequested(const QString &providerName);
void launchStopRequested(const QString &providerName);
void launchRestartRequested(const QString &providerName);
@@ -74,7 +76,7 @@ private:
QLabel *m_descriptionLabel = nullptr;
QLineEdit *m_nameEdit = nullptr;
QLineEdit *m_typeEdit = nullptr;
QLabel *m_protocolLabel = nullptr;
QPlainTextEdit *m_descriptionEdit = nullptr;
QLineEdit *m_urlEdit = nullptr;
QLabel *m_samplePreview = nullptr;

View File

@@ -125,6 +125,8 @@ public:
this, &ProvidersPageWidget::onApiKeySave);
connect(m_detailPane, &ProviderDetailPane::apiKeyClearRequested,
this, &ProvidersPageWidget::onApiKeyClear);
connect(m_detailPane, &ProviderDetailPane::apiKeyRevealRequested,
this, &ProvidersPageWidget::onApiKeyReveal);
connect(m_detailPane, &ProviderDetailPane::launchStartRequested,
this, &ProvidersPageWidget::onLaunchStart);
connect(m_detailPane, &ProviderDetailPane::launchStopRequested,
@@ -447,6 +449,16 @@ private slots:
m_detailPane->refreshKeyStatus(true);
}
void onApiKeyReveal()
{
if (!m_factory || !m_secrets || m_currentName.isEmpty())
return;
const auto *inst = m_factory->instanceByName(m_currentName);
if (!inst || inst->apiKeyRef.isEmpty())
return;
m_detailPane->showRevealedKey(m_secrets->readKeySync(inst->apiKeyRef));
}
void onApiKeyClear()
{
if (!m_factory || !m_secrets || m_currentName.isEmpty())

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Claude"
client_api = "Claude"
description = "Anthropic's hosted Claude API."
description = "Cloud (Anthropic). Claude Opus/Sonnet/Haiku via the Messages API."
url = "https://api.anthropic.com"
api_key_ref = "qodeassist/providers/Claude"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Codestral"
client_api = "Codestral"
description = "Mistral's Codestral FIM-capable code model API."
description = "Cloud (Mistral). Codestral — a code model with native fill-in-the-middle, great for completion."
url = "https://codestral.mistral.ai"
api_key_ref = "qodeassist/providers/Codestral"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Google AI"
client_api = "Google AI"
description = "Google AI Studio (Gemini) hosted API."
description = "Cloud (Google). Gemini models via Google AI Studio."
url = "https://generativelanguage.googleapis.com/v1beta"
api_key_ref = "qodeassist/providers/Google AI"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "llama.cpp"
client_api = "llama.cpp"
description = "Local llama.cpp server (llama-server)."
description = "Local (llama.cpp). Your own llama-server running GGUF models. Point the URL at your server (default :8080)."
url = "http://localhost:8080"
api_key_ref = "qodeassist/providers/llama.cpp"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "LM Studio (Chat Completions)"
client_api = "LM Studio (Chat Completions)"
description = "Local LM Studio server over the /v1/chat/completions endpoint."
description = "Local (LM Studio). The OpenAI Chat Completions API — the right pick for most LM Studio models."
url = "http://localhost:1234"
api_key_ref = "qodeassist/providers/LM Studio (Chat Completions)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "LM Studio (Responses API)"
client_api = "LM Studio (Responses API)"
description = "Local LM Studio server over the /v1/responses endpoint."
description = "Local (LM Studio). The newer Responses API — use only if your model needs it, otherwise pick LM Studio (Chat Completions)."
url = "http://localhost:1234"
api_key_ref = "qodeassist/providers/LM Studio (Responses API)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Mistral AI"
client_api = "Mistral AI"
description = "Mistral's hosted chat / completions API."
description = "Cloud (Mistral). Mistral chat/instruct models, incl. the Magistral reasoning model. For Mistral's FIM code model, use Codestral."
url = "https://api.mistral.ai"
api_key_ref = "qodeassist/providers/Mistral AI"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Ollama (OpenAI-compatible)"
client_api = "Ollama (OpenAI-compatible)"
description = "Local Ollama daemon spoken to via the OpenAI-compatible /v1 routes."
description = "Local (Ollama). The OpenAI-compatible /v1 routes — for OpenAI-style agents. For everyday use prefer Ollama (Native)."
url = "http://localhost:11434"
api_key_ref = "qodeassist/providers/Ollama (OpenAI-compatible)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "Ollama (Native)"
client_api = "Ollama (Native)"
description = "Default local Ollama daemon over its native /api/* endpoints."
description = "Local (Ollama). The default — native /api endpoints with the best support for FIM, thinking and tools. Use this for the bundled Ollama agents."
url = "http://localhost:11434"
api_key_ref = "qodeassist/providers/Ollama (Native)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "OpenAI (Chat Completions)"
client_api = "OpenAI (Chat Completions)"
description = "OpenAI's hosted /v1/chat/completions endpoint."
description = "Cloud (OpenAI). GPT models via the standard Chat Completions API. The default OpenAI choice."
url = "https://api.openai.com/v1"
api_key_ref = "qodeassist/providers/OpenAI (Chat Completions)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "OpenAI Compatible"
client_api = "OpenAI Compatible"
description = "Self-hosted OpenAI-compatible server (vLLM, TGI, ...). Edit the URL to match your deployment."
description = "Self-hosted, OpenAI-compatible server (vLLM, TGI, LiteLLM, …). Point the URL at your deployment."
url = "http://localhost:1234/v1"
api_key_ref = "qodeassist/providers/OpenAI Compatible"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "OpenAI (Responses API)"
client_api = "OpenAI (Responses API)"
description = "OpenAI's hosted /v1/responses endpoint."
description = "Cloud (OpenAI). GPT models via the newer Responses API (needed for some o-series reasoning models). If unsure, use OpenAI (Chat Completions)."
url = "https://api.openai.com/v1"
api_key_ref = "qodeassist/providers/OpenAI (Responses API)"

View File

@@ -2,7 +2,7 @@ schema_version = 1
name = "OpenRouter"
client_api = "OpenRouter"
description = "OpenRouter aggregator (https://openrouter.ai)."
description = "Cloud aggregator (openrouter.ai) — a single gateway to models from many providers (Anthropic, OpenAI, Google, Meta, …)."
url = "https://openrouter.ai/api"
api_key_ref = "qodeassist/providers/OpenRouter"