Skip to content

Commit d7a1c87

Browse files
refactor(dialogs): extract goal config into dedicated dialog
- GoalConfigWidget was embedded inline in EditScheduledTaskDialog, bloating the form and coupling unrelated concerns - Moving it into GoalAgentConfigDialog lets the scheduled task dialog stay compact (480px vs 700px) and opens config only on demand - Storing ScheduledTaskGoalConfig by value (m_goalConfigData) instead of reading live widget state simplifies taskResult() and avoids partial reads if the sub-dialog is never opened - Cron AI button now disables during the async request to prevent double-fires and gives visual feedback via "..." label - Table column sizing switched from resizeColumnsToContents() on every refresh to static ResizeMode assignments, eliminating repeated layout passes on the hot refresh path
1 parent 756a2af commit d7a1c87

6 files changed

Lines changed: 146 additions & 34 deletions

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ qt_add_executable(NotepadAI
202202
dialogs/ScheduledTaskDialog.h
203203
dialogs/EditScheduledTaskDialog.cpp
204204
dialogs/EditScheduledTaskDialog.h
205+
dialogs/GoalAgentConfigDialog.cpp
206+
dialogs/GoalAgentConfigDialog.h
205207
dialogs/EditTasksDialog.cpp
206208
dialogs/EditTasksDialog.h
207209
dialogs/EditMiniAppsDialog.cpp

src/dialogs/EditScheduledTaskDialog.cpp

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include <QDir>
2525
#include <QFileDialog>
2626
#include <QFormLayout>
27-
#include <QGroupBox>
2827
#include <QHBoxLayout>
2928
#include <QInputDialog>
3029
#include <QLabel>
@@ -40,7 +39,7 @@
4039
#include "AcpAgentRegistry.h"
4140
#include "ApplicationSettings.h"
4241
#include "CronExpression.h"
43-
#include "GoalConfigWidget.h"
42+
#include "GoalAgentConfigDialog.h"
4443
#include "NotepadNextApplication.h"
4544
#include "ai/CredentialStore.h"
4645
#include "ai/LlmHttpClient.h"
@@ -56,7 +55,7 @@ EditScheduledTaskDialog::EditScheduledTaskDialog(const ScheduledTaskDefinition &
5655
, m_original(def)
5756
{
5857
setWindowTitle(def.id.isEmpty() ? tr("Add Scheduled Task") : tr("Edit Scheduled Task"));
59-
resize(520, 700);
58+
resize(520, 480);
6059

6160
auto *mainLayout = new QVBoxLayout(this);
6261
auto *form = new QFormLayout();
@@ -131,27 +130,25 @@ EditScheduledTaskDialog::EditScheduledTaskDialog(const ScheduledTaskDefinition &
131130
mainLayout->addLayout(form);
132131

133132
// Goal section
133+
auto *goalRow = new QHBoxLayout();
134134
m_goalCheck = new QCheckBox(tr("Enable Goal Agent evaluation"), this);
135135
m_goalCheck->setChecked(def.hasGoalConfig);
136-
mainLayout->addWidget(m_goalCheck);
137-
138-
m_goalGroup = new QGroupBox(tr("Goal Configuration"), this);
139-
auto *goalGroupLayout = new QVBoxLayout(m_goalGroup);
140-
goalGroupLayout->setContentsMargins(6, 6, 6, 6);
141-
m_goalConfig = new GoalConfigWidget(agentRegistry, settings, m_goalGroup);
142-
goalGroupLayout->addWidget(m_goalConfig);
143-
144-
if (def.hasGoalConfig) {
145-
m_goalConfig->setCriteria(def.goalConfig.criteriaList);
146-
m_goalConfig->setAgentId(def.goalConfig.agentId);
147-
m_goalConfig->setMaxIterations(def.goalConfig.maxIterations);
148-
if (!def.goalConfig.promptTemplateId.isEmpty())
149-
m_goalConfig->setPromptTemplateId(def.goalConfig.promptTemplateId);
150-
}
151-
152-
mainLayout->addWidget(m_goalGroup);
153-
m_goalGroup->setVisible(def.hasGoalConfig);
154-
connect(m_goalCheck, &QCheckBox::toggled, m_goalGroup, &QGroupBox::setVisible);
136+
goalRow->addWidget(m_goalCheck);
137+
m_goalConfigBtn = new QPushButton(tr("Configure..."), this);
138+
m_goalConfigBtn->setEnabled(def.hasGoalConfig);
139+
goalRow->addWidget(m_goalConfigBtn);
140+
goalRow->addStretch();
141+
mainLayout->addLayout(goalRow);
142+
143+
if (def.hasGoalConfig)
144+
m_goalConfigData = def.goalConfig;
145+
146+
connect(m_goalCheck, &QCheckBox::toggled, m_goalConfigBtn, &QPushButton::setEnabled);
147+
connect(m_goalConfigBtn, &QPushButton::clicked, this, [this]() {
148+
GoalAgentConfigDialog dlg(m_goalConfigData, m_agentRegistry, m_settings, this);
149+
if (dlg.exec() == QDialog::Accepted)
150+
m_goalConfigData = dlg.goalConfig();
151+
});
155152

156153
// Buttons
157154
auto *btnLayout = new QHBoxLayout();
@@ -247,11 +244,7 @@ ScheduledTaskDefinition EditScheduledTaskDialog::taskResult() const
247244

248245
def.hasGoalConfig = m_goalCheck->isChecked();
249246
if (def.hasGoalConfig) {
250-
const GoalConfigResult gcr = m_goalConfig->result();
251-
def.goalConfig.criteriaList = gcr.criteriaList;
252-
def.goalConfig.agentId = gcr.agentId;
253-
def.goalConfig.maxIterations = gcr.maxIterations;
254-
def.goalConfig.promptTemplateId = gcr.promptTemplateId;
247+
def.goalConfig = m_goalConfigData;
255248
} else {
256249
def.goalConfig = ScheduledTaskGoalConfig{};
257250
}
@@ -315,11 +308,16 @@ void EditScheduledTaskDialog::onCronHelperClicked()
315308
req.maxTokens = 50;
316309
req.idleTimeoutSec = 30;
317310

311+
m_cronHelperBtn->setEnabled(false);
312+
m_cronHelperBtn->setText(tr("..."));
313+
318314
auto *accumulated = new QString();
319315
connect(client, &ai::ILlmHttpClient::tokenReceived, this, [accumulated](const QString &token) {
320316
*accumulated += token;
321317
});
322318
connect(client, &ai::ILlmHttpClient::streamEnded, this, [this, client, accumulated]() {
319+
m_cronHelperBtn->setEnabled(true);
320+
m_cronHelperBtn->setText(tr("AI"));
323321
const QString cronExpr = accumulated->trimmed();
324322
auto parsed = CronExpression::parse(cronExpr);
325323
if (parsed && parsed->isValid()) {
@@ -332,6 +330,8 @@ void EditScheduledTaskDialog::onCronHelperClicked()
332330
client->deleteLater();
333331
});
334332
connect(client, &ai::ILlmHttpClient::errorOccurred, this, [this, client, accumulated](int, const QString &msg) {
333+
m_cronHelperBtn->setEnabled(true);
334+
m_cronHelperBtn->setText(tr("AI"));
335335
QMessageBox::warning(this, tr("AI Error"), msg);
336336
delete accumulated;
337337
client->deleteLater();

src/dialogs/EditScheduledTaskDialog.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@
2525

2626
class AcpAgentRegistry;
2727
class ApplicationSettings;
28-
class GoalConfigWidget;
2928
class QCheckBox;
3029
class QComboBox;
31-
class QGroupBox;
3230
class QLabel;
3331
class QLineEdit;
3432
class QPlainTextEdit;
@@ -82,8 +80,8 @@ private slots:
8280

8381
// Goal section
8482
QCheckBox *m_goalCheck;
85-
QGroupBox *m_goalGroup;
86-
GoalConfigWidget *m_goalConfig;
83+
QPushButton *m_goalConfigBtn;
84+
ScheduledTaskGoalConfig m_goalConfigData;
8785

8886
QPushButton *m_saveBtn;
8987
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* This file is part of Notepad Next.
3+
* Copyright 2026 NotepadAI contributors
4+
*
5+
* Notepad Next is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* Notepad Next is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with Notepad Next. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#include "GoalAgentConfigDialog.h"
20+
21+
#include <QDialogButtonBox>
22+
#include <QVBoxLayout>
23+
24+
#include "GoalConfigWidget.h"
25+
26+
GoalAgentConfigDialog::GoalAgentConfigDialog(const ScheduledTaskGoalConfig &config,
27+
AcpAgentRegistry *registry,
28+
ApplicationSettings *settings,
29+
QWidget *parent)
30+
: QDialog(parent)
31+
{
32+
setWindowTitle(tr("Goal Configuration"));
33+
setMinimumWidth(480);
34+
35+
auto *layout = new QVBoxLayout(this);
36+
layout->setSpacing(8);
37+
38+
m_goalConfig = new GoalConfigWidget(registry, settings, this);
39+
layout->addWidget(m_goalConfig);
40+
41+
if (!config.criteriaList.isEmpty())
42+
m_goalConfig->setCriteria(config.criteriaList);
43+
if (!config.agentId.isEmpty())
44+
m_goalConfig->setAgentId(config.agentId);
45+
if (config.maxIterations > 0)
46+
m_goalConfig->setMaxIterations(config.maxIterations);
47+
if (!config.promptTemplateId.isEmpty())
48+
m_goalConfig->setPromptTemplateId(config.promptTemplateId);
49+
50+
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
51+
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
52+
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
53+
layout->addWidget(buttons);
54+
}
55+
56+
ScheduledTaskGoalConfig GoalAgentConfigDialog::goalConfig() const
57+
{
58+
ScheduledTaskGoalConfig cfg;
59+
const auto gcr = m_goalConfig->result();
60+
cfg.criteriaList = gcr.criteriaList;
61+
cfg.agentId = gcr.agentId;
62+
cfg.maxIterations = gcr.maxIterations;
63+
cfg.promptTemplateId = gcr.promptTemplateId;
64+
return cfg;
65+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* This file is part of Notepad Next.
3+
* Copyright 2026 NotepadAI contributors
4+
*
5+
* Notepad Next is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* Notepad Next is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with Notepad Next. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#ifndef GOAL_AGENT_CONFIG_DIALOG_H
20+
#define GOAL_AGENT_CONFIG_DIALOG_H
21+
22+
#include <QDialog>
23+
24+
#include "ScheduledTaskDefinition.h"
25+
26+
class AcpAgentRegistry;
27+
class ApplicationSettings;
28+
class GoalConfigWidget;
29+
30+
class GoalAgentConfigDialog : public QDialog
31+
{
32+
Q_OBJECT
33+
34+
public:
35+
explicit GoalAgentConfigDialog(const ScheduledTaskGoalConfig &config,
36+
AcpAgentRegistry *registry,
37+
ApplicationSettings *settings,
38+
QWidget *parent = nullptr);
39+
40+
ScheduledTaskGoalConfig goalConfig() const;
41+
42+
private:
43+
GoalConfigWidget *m_goalConfig;
44+
};
45+
46+
#endif // GOAL_AGENT_CONFIG_DIALOG_H

src/dialogs/ScheduledTaskDialog.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ ScheduledTaskDialog::ScheduledTaskDialog(ScheduledTaskRegistry *registry,
5353
m_table = new QTableWidget(this);
5454
m_table->setColumnCount(4);
5555
m_table->setHorizontalHeaderLabels({tr("Enabled"), tr("Name"), tr("Cron"), tr("Next Fire")});
56-
m_table->horizontalHeader()->setStretchLastSection(true);
56+
m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
57+
m_table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
58+
m_table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
59+
m_table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
5760
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
5861
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
5962
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
@@ -198,6 +201,4 @@ void ScheduledTaskDialog::refreshTable()
198201
}
199202
m_table->setItem(i, 3, new QTableWidgetItem(nextStr));
200203
}
201-
202-
m_table->resizeColumnsToContents();
203204
}

0 commit comments

Comments
 (0)