Modules/Taskboard/public/SessionPanel.hpp
Шурупов Илья Викторович c5de549771 Taskboard: magnetic full view for a task card and session presets
TreeView gains a third magnetic camera level past the detailed cards. Once a
card fills fullViewFill of the view, zooming further in pulls it toward the
full view with resistance and springs back on release; pushing past
levelPull commits. The card then springs out of its graph slot on an
underdamped spring to cover the whole view while the rest of the graph and
its links fade behind it. Zooming out pulls it back the same way, Escape
leaves at once. Cards show fullContent() at that level, or reuse content()
while fullContent() is empty, so detail levels stay declared per card.

The task board opens the full-view task in its panels and, for now, shows
the same card body in the full view.

Session panel:
- named presets of launch parameters (model, harness, effort, mode) are
  stored in $XDG_CONFIG_HOME/taskboard/session-presets.json through the
  injectable FileSystem; the preset picker sits above the parameters,
  shows "Custom" when the task matches no preset, and applies a preset to
  the open task;
- parameters live in a collapsible "Parameters" section above the session
  buttons, with the current settings as its summary;
- the "Message the agent" field and the now unused TaskStore::sendMessage
  path are removed.

SessionTab and SubrouterStatus move out of TaskTreeView.cpp into
SessionPanel.{hpp,cpp}.
2026-10-24 17:21:56 +03:00

122 lines
3.7 KiB
C++

#pragma once
#include "Button.hpp"
#include "Collapsible.hpp"
#include "Label.hpp"
#include "Menus.hpp"
#include "SessionPresets.hpp"
#include "TaskBoard.hpp"
#include "TaskStore.hpp"
#include "TextField.hpp"
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>
namespace tp::taskboard {
class SubrouterStatus : public ui::Widget {
public:
SubrouterStatus();
void setInfo(const SubrouterInfo& info);
ui::Label hint;
ui::Label accounts;
};
class SessionPresetPicker : public ui::Widget {
public:
explicit SessionPresetPicker(SessionPresets& presets);
void showSettings(const LaunchSettings& settings);
void openNaming();
[[nodiscard]] bool isNaming() const { return mNamingRow.isVisible(); }
ui::Dropdown preset;
ui::Button saveAs{ "Save as preset..." };
ui::Button remove{ "\u2715" };
ui::TextField name;
ui::Button save{ "Save" };
ui::Button cancel{ "Cancel" };
ui::Label problem;
void setOnApplied(std::function<void(const LaunchSettings&)> callback) { mOnApplied = std::move(callback); }
void setCurrentSettings(std::function<LaunchSettings()> current) { mCurrent = std::move(current); }
static constexpr const char* kCustomOption = "Custom";
private:
void buildLayout();
void bindControls();
void refreshOptions();
void presetChosen(long option);
void commitName();
void closeNaming();
void removeSelected();
[[nodiscard]] std::optional<size_t> selectedPreset() const;
SessionPresets& mPresets;
std::optional<size_t> mShownPreset;
bool mLoading = false;
ui::Label mLabel{ "Preset" };
ui::Widget mPresetRow;
ui::Widget mNamingRow;
std::function<void(const LaunchSettings&)> mOnApplied;
std::function<LaunchSettings()> mCurrent;
};
class SessionTab : public ui::Widget {
public:
SessionTab(TaskBoard& board, SessionPresets& presetStore);
void setSubrouterInfo(const SubrouterInfo& info) { subrouter.setInfo(info); }
void showTask(std::optional<ui::NodeId> id);
void setAgentOptions(AgentOptions options);
void setStore(TaskStore* store) { mStore = store; }
[[nodiscard]] bool isOfferingRestart() const { return mRestartRow.isVisible(); }
ui::Label state;
SessionPresetPicker presets;
ui::Collapsible parameters{ "Parameters" };
ui::Dropdown model;
ui::Dropdown harness;
ui::Dropdown effort;
ui::Dropdown permissionMode;
ui::Button startSession{ "Start session" };
ui::Button stopSession{ "Stop" };
ui::Button openSession{ "Open session" };
ui::Label restartHint;
ui::Button restartKeep{ "Restart, keep conversation" };
ui::Button restartFresh{ "Restart fresh" };
SubrouterStatus subrouter;
void setOnChanged(std::function<void()> callback) { mOnChanged = std::move(callback); }
void setOnOpenSession(std::function<void(ui::NodeId)> callback) { mOnOpenSession = std::move(callback); }
private:
void buildLayout();
void buildParameters();
void bindControls();
void change(const std::function<void(Task&)>& edit);
void applyPreset(const LaunchSettings& settings);
void showSettings(const Task& task);
void refreshControls(const Task& task);
void refreshRestart(const Task& task);
[[nodiscard]] std::string parametersSummary(const Task& task) const;
[[nodiscard]] static long optionIndex(const std::vector<std::string>& values, const std::string& value);
TaskBoard& mBoard;
TaskStore* mStore = nullptr;
std::optional<ui::NodeId> mShown;
bool mLoading = false;
AgentOptions mOptions = offlineAgentOptions();
ui::Widget mControls;
std::vector<std::unique_ptr<ui::Widget>> mSettingRows;
std::vector<std::unique_ptr<ui::Label>> mSettingLabels;
ui::Widget mRestartRow;
std::function<void()> mOnChanged;
std::function<void(ui::NodeId)> mOnOpenSession;
};
}