feat(ui): wählbares Listen-Icon und aufgeräumter Task-Detail-Header
Listen bekommen eine Icon-Spalte (Migration AddListIcon) und einen Icon-Picker in den Listeneinstellungen; 34 kuratierte Geometrien aus der Icon-Bibliothek, Fallback auf "Folder" bei unbekanntem Key. Der Metadata-Footer im Task-Detail entfällt; created-at wandert in die Header-Zeile neben das ID-Badge, der Close-Button (und CloseDetailsCommand) fällt weg.
This commit is contained in:
@@ -19,6 +19,7 @@ public class ListEntityConfiguration : IEntityTypeConfiguration<ListEntity>
|
|||||||
builder.Property(l => l.SortOrder).HasColumnName("sort_order").IsRequired().HasDefaultValue(0);
|
builder.Property(l => l.SortOrder).HasColumnName("sort_order").IsRequired().HasDefaultValue(0);
|
||||||
builder.Property(l => l.IsManual).HasColumnName("is_manual").IsRequired().HasDefaultValue(false);
|
builder.Property(l => l.IsManual).HasColumnName("is_manual").IsRequired().HasDefaultValue(false);
|
||||||
builder.Property(l => l.FindingsTracked).HasColumnName("findings_tracked").IsRequired().HasDefaultValue(false);
|
builder.Property(l => l.FindingsTracked).HasColumnName("findings_tracked").IsRequired().HasDefaultValue(false);
|
||||||
|
builder.Property(l => l.Icon).HasColumnName("icon");
|
||||||
|
|
||||||
builder.HasIndex(l => l.SortOrder).HasDatabaseName("idx_lists_sort");
|
builder.HasIndex(l => l.SortOrder).HasDatabaseName("idx_lists_sort");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,978 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using ClaudeDo.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ClaudeDo.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ClaudeDoDbContext))]
|
||||||
|
[Migration("20260828084750_AddListIcon")]
|
||||||
|
partial class AddListIcon
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "8.0.11");
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.AppSettingsEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoContinueOnUsageLimit")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("auto_continue_on_usage_limit");
|
||||||
|
|
||||||
|
b.Property<string>("CentralWorktreeRoot")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("central_worktree_root");
|
||||||
|
|
||||||
|
b.Property<int>("DailyPrepMaxTasks")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(5)
|
||||||
|
.HasColumnName("daily_prep_max_tasks");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultClaudeInstructions")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("")
|
||||||
|
.HasColumnName("default_claude_instructions");
|
||||||
|
|
||||||
|
b.Property<int>("DefaultMaxTurns")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(40)
|
||||||
|
.HasColumnName("default_max_turns");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultModel")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("sonnet")
|
||||||
|
.HasColumnName("default_model");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultPermissionMode")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("bypassPermissions")
|
||||||
|
.HasColumnName("default_permission_mode");
|
||||||
|
|
||||||
|
b.Property<int>("MaxParallelExecutions")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(1)
|
||||||
|
.HasColumnName("max_parallel_executions");
|
||||||
|
|
||||||
|
b.Property<int>("MaxTurnsCeiling")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(80)
|
||||||
|
.HasColumnName("max_turns_ceiling");
|
||||||
|
|
||||||
|
b.Property<string>("ModelPresets")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("model_presets");
|
||||||
|
|
||||||
|
b.Property<int>("NextTaskNumber")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(1)
|
||||||
|
.HasColumnName("next_task_number");
|
||||||
|
|
||||||
|
b.Property<string>("RepoImportFolders")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("repo_import_folders");
|
||||||
|
|
||||||
|
b.Property<string>("ReportExcludedPaths")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("report_excluded_paths");
|
||||||
|
|
||||||
|
b.Property<string>("SessionSkills")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("session_skills");
|
||||||
|
|
||||||
|
b.Property<int>("StandupWeekday")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(3)
|
||||||
|
.HasColumnName("standup_weekday");
|
||||||
|
|
||||||
|
b.Property<int>("UsageGateFiveHourPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(80)
|
||||||
|
.HasColumnName("usage_gate_five_hour_pct");
|
||||||
|
|
||||||
|
b.Property<int>("UsageGateSevenDayPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(90)
|
||||||
|
.HasColumnName("usage_gate_seven_day_pct");
|
||||||
|
|
||||||
|
b.Property<int>("UsageThrottleFiveHourHardPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(65)
|
||||||
|
.HasColumnName("usage_throttle_five_hour_hard_pct");
|
||||||
|
|
||||||
|
b.Property<int>("UsageThrottleFiveHourSoftPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(50)
|
||||||
|
.HasColumnName("usage_throttle_five_hour_soft_pct");
|
||||||
|
|
||||||
|
b.Property<int>("UsageThrottleSevenDayHardPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(65)
|
||||||
|
.HasColumnName("usage_throttle_seven_day_hard_pct");
|
||||||
|
|
||||||
|
b.Property<int>("UsageThrottleSevenDaySoftPct")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(50)
|
||||||
|
.HasColumnName("usage_throttle_seven_day_soft_pct");
|
||||||
|
|
||||||
|
b.Property<int>("WorktreeAutoCleanupDays")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(7)
|
||||||
|
.HasColumnName("worktree_auto_cleanup_days");
|
||||||
|
|
||||||
|
b.Property<bool>("WorktreeAutoCleanupEnabled")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("worktree_auto_cleanup_enabled");
|
||||||
|
|
||||||
|
b.Property<string>("WorktreeStrategy")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("sibling")
|
||||||
|
.HasColumnName("worktree_strategy");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("app_settings", (string)null);
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
AutoContinueOnUsageLimit = false,
|
||||||
|
DailyPrepMaxTasks = 5,
|
||||||
|
DefaultClaudeInstructions = "",
|
||||||
|
DefaultMaxTurns = 40,
|
||||||
|
DefaultModel = "sonnet",
|
||||||
|
DefaultPermissionMode = "auto",
|
||||||
|
MaxParallelExecutions = 1,
|
||||||
|
MaxTurnsCeiling = 80,
|
||||||
|
NextTaskNumber = 1,
|
||||||
|
StandupWeekday = 3,
|
||||||
|
UsageGateFiveHourPct = 80,
|
||||||
|
UsageGateSevenDayPct = 90,
|
||||||
|
UsageThrottleFiveHourHardPct = 65,
|
||||||
|
UsageThrottleFiveHourSoftPct = 50,
|
||||||
|
UsageThrottleSevenDayHardPct = 65,
|
||||||
|
UsageThrottleSevenDaySoftPct = 50,
|
||||||
|
WorktreeAutoCleanupDays = 7,
|
||||||
|
WorktreeAutoCleanupEnabled = false,
|
||||||
|
WorktreeStrategy = "sibling"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.DailyNoteEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<DateOnly>("Date")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("note_date");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("sort_order");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Date");
|
||||||
|
|
||||||
|
b.ToTable("daily_notes", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.ListConfigEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ListId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("list_id");
|
||||||
|
|
||||||
|
b.Property<string>("AgentPath")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("agent_path");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxTurns")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("max_turns");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("PermissionMode")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("permission_mode");
|
||||||
|
|
||||||
|
b.Property<string>("SessionSkills")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("session_skills");
|
||||||
|
|
||||||
|
b.Property<string>("SystemPrompt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("system_prompt");
|
||||||
|
|
||||||
|
b.Property<int?>("TicketProjectId")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("ticket_project_id");
|
||||||
|
|
||||||
|
b.Property<string>("VerifyCommand")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("verify_command");
|
||||||
|
|
||||||
|
b.HasKey("ListId");
|
||||||
|
|
||||||
|
b.ToTable("list_config", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.ListEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultCommitType")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("chore")
|
||||||
|
.HasColumnName("default_commit_type");
|
||||||
|
|
||||||
|
b.Property<bool>("FindingsTracked")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("findings_tracked");
|
||||||
|
|
||||||
|
b.Property<string>("Icon")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("icon");
|
||||||
|
|
||||||
|
b.Property<bool>("IsManual")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("is_manual");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0)
|
||||||
|
.HasColumnName("sort_order");
|
||||||
|
|
||||||
|
b.Property<string>("WorkingDir")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("working_dir");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SortOrder")
|
||||||
|
.HasDatabaseName("idx_lists_sort");
|
||||||
|
|
||||||
|
b.ToTable("lists", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.PrimeScheduleEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<int>("Days")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(31)
|
||||||
|
.HasColumnName("days_of_week");
|
||||||
|
|
||||||
|
b.Property<bool>("Enabled")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(true)
|
||||||
|
.HasColumnName("enabled");
|
||||||
|
|
||||||
|
b.Property<string>("Kind")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("ping")
|
||||||
|
.HasColumnName("action_kind");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LastRunAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("last_run_at");
|
||||||
|
|
||||||
|
b.Property<string>("PromptOverride")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("prompt_override");
|
||||||
|
|
||||||
|
b.Property<TimeSpan>("TimeOfDay")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("time_of_day");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("prime_schedules", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.SessionSkillEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("AddedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("added_at");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<string>("PinnedRef")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("pinned_ref");
|
||||||
|
|
||||||
|
b.Property<string>("SourceUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("source_url");
|
||||||
|
|
||||||
|
b.Property<string>("Subpath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("subpath");
|
||||||
|
|
||||||
|
b.HasKey("Name");
|
||||||
|
|
||||||
|
b.ToTable("session_skills", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.SubtaskEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<bool>("Completed")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("completed");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<int>("OrderNum")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("order_num");
|
||||||
|
|
||||||
|
b.Property<string>("TaskId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("task_id");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("title");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TaskId")
|
||||||
|
.HasDatabaseName("idx_subtasks_task_id");
|
||||||
|
|
||||||
|
b.ToTable("subtasks", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskAttachmentEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<long>("ByteSize")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("byte_size");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<string>("FileName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("file_name");
|
||||||
|
|
||||||
|
b.Property<string>("TaskId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("task_id");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TaskId")
|
||||||
|
.HasDatabaseName("idx_task_attachments_task_id");
|
||||||
|
|
||||||
|
b.ToTable("task_attachments", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<string>("AgentPath")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("agent_path");
|
||||||
|
|
||||||
|
b.Property<string>("BlockedByTaskId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("blocked_by_task_id");
|
||||||
|
|
||||||
|
b.Property<string>("CommitType")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("chore")
|
||||||
|
.HasColumnName("commit_type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_by");
|
||||||
|
|
||||||
|
b.Property<string>("DependsOnTaskId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("depends_on_task_id");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<int?>("FailureMaxTurns")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("failure_max_turns");
|
||||||
|
|
||||||
|
b.Property<string>("FailureReason")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("failure_reason");
|
||||||
|
|
||||||
|
b.Property<int?>("FailureTurnsUsed")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("failure_turns_used");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("FinishedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("finished_at");
|
||||||
|
|
||||||
|
b.Property<string>("HandlerBaseCommit")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("handler_base_commit");
|
||||||
|
|
||||||
|
b.Property<string>("HandlerHeadCommit")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("handler_head_commit");
|
||||||
|
|
||||||
|
b.Property<string>("InteractiveSessionId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("interactive_session_id");
|
||||||
|
|
||||||
|
b.Property<bool>("IsManual")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("is_manual");
|
||||||
|
|
||||||
|
b.Property<bool>("IsMyDay")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("is_my_day");
|
||||||
|
|
||||||
|
b.Property<bool>("IsStarred")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("is_starred");
|
||||||
|
|
||||||
|
b.Property<string>("ListId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("list_id");
|
||||||
|
|
||||||
|
b.Property<string>("LogPath")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("log_path");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxTurns")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("max_turns");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Notes")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("notes");
|
||||||
|
|
||||||
|
b.Property<int>("Number")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.Property<string>("ParentTaskId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("parent_task_id");
|
||||||
|
|
||||||
|
b.Property<string>("PermissionMode")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("permission_mode");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("PlanningFinalizedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("planning_finalized_at");
|
||||||
|
|
||||||
|
b.Property<string>("PlanningPhase")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("none")
|
||||||
|
.HasColumnName("planning_phase");
|
||||||
|
|
||||||
|
b.Property<string>("PlanningSessionId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("planning_session_id");
|
||||||
|
|
||||||
|
b.Property<string>("PlanningSessionToken")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("planning_session_token");
|
||||||
|
|
||||||
|
b.Property<string>("Result")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("result");
|
||||||
|
|
||||||
|
b.Property<string>("ReviewFeedback")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("review_feedback");
|
||||||
|
|
||||||
|
b.Property<int>("RoadblockCount")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0)
|
||||||
|
.HasColumnName("roadblock_count");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ScheduledFor")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("scheduled_for");
|
||||||
|
|
||||||
|
b.Property<string>("SessionSkills")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("session_skills");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(0)
|
||||||
|
.HasColumnName("sort_order");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("StartedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("started_at");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("status");
|
||||||
|
|
||||||
|
b.Property<string>("SystemPrompt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("system_prompt");
|
||||||
|
|
||||||
|
b.Property<string>("TicketRef")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("ticket_ref");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("title");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UsageLimitAutoContinuedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("usage_limit_auto_continued_at");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BlockedByTaskId")
|
||||||
|
.HasDatabaseName("idx_tasks_blocked_by");
|
||||||
|
|
||||||
|
b.HasIndex("DependsOnTaskId")
|
||||||
|
.HasDatabaseName("idx_tasks_depends_on");
|
||||||
|
|
||||||
|
b.HasIndex("ListId")
|
||||||
|
.HasDatabaseName("idx_tasks_list_id");
|
||||||
|
|
||||||
|
b.HasIndex("Number")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("idx_tasks_number");
|
||||||
|
|
||||||
|
b.HasIndex("ParentTaskId")
|
||||||
|
.HasDatabaseName("idx_tasks_parent_task_id");
|
||||||
|
|
||||||
|
b.HasIndex("Status")
|
||||||
|
.HasDatabaseName("idx_tasks_status");
|
||||||
|
|
||||||
|
b.HasIndex("ListId", "SortOrder")
|
||||||
|
.HasDatabaseName("idx_tasks_list_sort");
|
||||||
|
|
||||||
|
b.ToTable("tasks", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskRunEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<int?>("CacheReadTokens")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("cache_read_tokens");
|
||||||
|
|
||||||
|
b.Property<int?>("CacheWriteTokens")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("cache_write_tokens");
|
||||||
|
|
||||||
|
b.Property<string>("ErrorMarkdown")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("error_markdown");
|
||||||
|
|
||||||
|
b.Property<string>("Errors")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("errors");
|
||||||
|
|
||||||
|
b.Property<int?>("ExitCode")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("exit_code");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("FinishedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("finished_at");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRetry")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("is_retry");
|
||||||
|
|
||||||
|
b.Property<string>("LogPath")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("log_path");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Prompt")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("prompt");
|
||||||
|
|
||||||
|
b.Property<string>("ResultMarkdown")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("result_markdown");
|
||||||
|
|
||||||
|
b.Property<string>("ResultSubtype")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("result_subtype");
|
||||||
|
|
||||||
|
b.Property<int>("RunNumber")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("run_number");
|
||||||
|
|
||||||
|
b.Property<string>("SessionId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("session_id");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("StartedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("started_at");
|
||||||
|
|
||||||
|
b.Property<string>("StructuredOutputJson")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("structured_output");
|
||||||
|
|
||||||
|
b.Property<string>("TaskId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("task_id");
|
||||||
|
|
||||||
|
b.Property<string>("TerminalReason")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("terminal_reason");
|
||||||
|
|
||||||
|
b.Property<int?>("TokensIn")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("tokens_in");
|
||||||
|
|
||||||
|
b.Property<int?>("TokensOut")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("tokens_out");
|
||||||
|
|
||||||
|
b.Property<int?>("TurnCount")
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasColumnName("turn_count");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TaskId")
|
||||||
|
.HasDatabaseName("idx_task_runs_task_id");
|
||||||
|
|
||||||
|
b.ToTable("task_runs", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.WeekReportEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<DateOnly>("EndDate")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("end_date");
|
||||||
|
|
||||||
|
b.Property<DateTime>("GeneratedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("generated_at");
|
||||||
|
|
||||||
|
b.Property<string>("Markdown")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("markdown");
|
||||||
|
|
||||||
|
b.Property<DateOnly>("StartDate")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("start_date");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("StartDate", "EndDate")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("week_reports", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.WorktreeEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("TaskId")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("task_id");
|
||||||
|
|
||||||
|
b.Property<string>("BaseCommit")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("base_commit");
|
||||||
|
|
||||||
|
b.Property<string>("BranchName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("branch_name");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<string>("DiffStat")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("diff_stat");
|
||||||
|
|
||||||
|
b.Property<string>("HeadCommit")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("head_commit");
|
||||||
|
|
||||||
|
b.Property<string>("MergeCommit")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("merge_commit");
|
||||||
|
|
||||||
|
b.Property<string>("Path")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("path");
|
||||||
|
|
||||||
|
b.Property<string>("State")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValue("active")
|
||||||
|
.HasColumnName("state");
|
||||||
|
|
||||||
|
b.HasKey("TaskId");
|
||||||
|
|
||||||
|
b.ToTable("worktrees", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.ListConfigEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.ListEntity", "List")
|
||||||
|
.WithOne("Config")
|
||||||
|
.HasForeignKey("ClaudeDo.Data.Models.ListConfigEntity", "ListId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("List");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.SubtaskEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", "Task")
|
||||||
|
.WithMany("Subtasks")
|
||||||
|
.HasForeignKey("TaskId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Task");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskAttachmentEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", "Task")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TaskId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Task");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("BlockedByTaskId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DependsOnTaskId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.ListEntity", "List")
|
||||||
|
.WithMany("Tasks")
|
||||||
|
.HasForeignKey("ListId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", "Parent")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("ParentTaskId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("List");
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskRunEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", "Task")
|
||||||
|
.WithMany("Runs")
|
||||||
|
.HasForeignKey("TaskId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Task");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.WorktreeEntity", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("ClaudeDo.Data.Models.TaskEntity", "Task")
|
||||||
|
.WithOne("Worktree")
|
||||||
|
.HasForeignKey("ClaudeDo.Data.Models.WorktreeEntity", "TaskId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Task");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.ListEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Config");
|
||||||
|
|
||||||
|
b.Navigation("Tasks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("ClaudeDo.Data.Models.TaskEntity", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Children");
|
||||||
|
|
||||||
|
b.Navigation("Runs");
|
||||||
|
|
||||||
|
b.Navigation("Subtasks");
|
||||||
|
|
||||||
|
b.Navigation("Worktree");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ClaudeDo.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddListIcon : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "icon",
|
||||||
|
table: "lists",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "icon",
|
||||||
|
table: "lists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -287,6 +287,10 @@ namespace ClaudeDo.Data.Migrations
|
|||||||
.HasDefaultValue(false)
|
.HasDefaultValue(false)
|
||||||
.HasColumnName("findings_tracked");
|
.HasColumnName("findings_tracked");
|
||||||
|
|
||||||
|
b.Property<string>("Icon")
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasColumnName("icon");
|
||||||
|
|
||||||
b.Property<bool>("IsManual")
|
b.Property<bool>("IsManual")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER")
|
.HasColumnType("INTEGER")
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ public sealed class ListEntity
|
|||||||
// When true the project's .claudedo/ findings store is committed with the repo; when false it
|
// When true the project's .claudedo/ findings store is committed with the repo; when false it
|
||||||
// is kept out of git via .git/info/exclude (see FindingsStore).
|
// is kept out of git via .git/info/exclude (see FindingsStore).
|
||||||
public bool FindingsTracked { get; set; }
|
public bool FindingsTracked { get; set; }
|
||||||
|
// Icon key into the UI's icon library (e.g. "Star"); null = the default folder icon.
|
||||||
|
public string? Icon { get; set; }
|
||||||
|
|
||||||
// Navigation properties
|
// Navigation properties
|
||||||
public ListConfigEntity? Config { get; set; }
|
public ListConfigEntity? Config { get; set; }
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public record ConflictDocumentDto(string Path, bool IsBinary, IReadOnlyList<Merg
|
|||||||
|
|
||||||
public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string? Base, string Theirs);
|
public record MergeSegmentDto(bool IsConflict, string Text, string Ours, string? Base, string Theirs);
|
||||||
|
|
||||||
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false);
|
public record UpdateListDto(string Id, string Name, string? WorkingDir, string DefaultCommitType, bool IsManual = false, bool FindingsTracked = false, string? Icon = null);
|
||||||
|
|
||||||
// TicketProjectId is tri-state on purpose: a caller that doesn't own the field (anything but the
|
// TicketProjectId is tri-state on purpose: a caller that doesn't own the field (anything but the
|
||||||
// list-settings modal) must not be able to clear it by omission — SetConfigAsync copies the entity
|
// list-settings modal) must not be able to clear it by omission — SetConfigAsync copies the entity
|
||||||
|
|||||||
@@ -261,7 +261,6 @@
|
|||||||
"killSessionTip": "Laufende Sitzung beenden",
|
"killSessionTip": "Laufende Sitzung beenden",
|
||||||
"sendToQueue": "In Warteschlange einreihen",
|
"sendToQueue": "In Warteschlange einreihen",
|
||||||
"sendToQueueTip": "Diese Aufgabe in die Warteschlange einreihen, damit Claude sie beim nächsten Lauf übernimmt",
|
"sendToQueueTip": "Diese Aufgabe in die Warteschlange einreihen, damit Claude sie beim nächsten Lauf übernimmt",
|
||||||
"closeTip": "Schließen",
|
|
||||||
"copyTaskIdTip": "Aufgaben-ID kopieren",
|
"copyTaskIdTip": "Aufgaben-ID kopieren",
|
||||||
"starTip": "Favorit",
|
"starTip": "Favorit",
|
||||||
"agentSettingsTip": "Agent-Einstellungen",
|
"agentSettingsTip": "Agent-Einstellungen",
|
||||||
@@ -396,6 +395,9 @@
|
|||||||
"manualListHint": "Neue Aufgaben in dieser Liste sind zunächst manuell: kein Einreihen, Ausführen oder Verfeinern, und die Automatik überspringt sie. Eine handgesteuerte Sitzung kannst du weiterhin öffnen.",
|
"manualListHint": "Neue Aufgaben in dieser Liste sind zunächst manuell: kein Einreihen, Ausführen oder Verfeinern, und die Automatik überspringt sie. Eine handgesteuerte Sitzung kannst du weiterhin öffnen.",
|
||||||
"findingsTracked": "Findings-Ordner .claudedo einchecken",
|
"findingsTracked": "Findings-Ordner .claudedo einchecken",
|
||||||
"findingsTrackedHint": "Aus: der Ordner bleibt über .git/info/exclude aus git heraus. An: Findings reisen mit dem Repo.",
|
"findingsTrackedHint": "Aus: der Ordner bleibt über .git/info/exclude aus git heraus. An: Findings reisen mit dem Repo.",
|
||||||
|
"sectionIcon": "ICON",
|
||||||
|
"icon": "Listen-Icon",
|
||||||
|
"iconHint": "Wird in der Seitenleiste neben dem Listennamen angezeigt.",
|
||||||
"sectionAgent": "AGENT",
|
"sectionAgent": "AGENT",
|
||||||
"resetAgentSettings": "Agent-Einstellungen zurücksetzen",
|
"resetAgentSettings": "Agent-Einstellungen zurücksetzen",
|
||||||
"sectionVerify": "VERIFIKATION",
|
"sectionVerify": "VERIFIKATION",
|
||||||
|
|||||||
@@ -261,7 +261,6 @@
|
|||||||
"killSessionTip": "Kill the running session",
|
"killSessionTip": "Kill the running session",
|
||||||
"sendToQueue": "Send to queue",
|
"sendToQueue": "Send to queue",
|
||||||
"sendToQueueTip": "Queue this task so Claude picks it up on the next run",
|
"sendToQueueTip": "Queue this task so Claude picks it up on the next run",
|
||||||
"closeTip": "Close",
|
|
||||||
"copyTaskIdTip": "Copy task ID",
|
"copyTaskIdTip": "Copy task ID",
|
||||||
"starTip": "Star",
|
"starTip": "Star",
|
||||||
"agentSettingsTip": "Agent settings",
|
"agentSettingsTip": "Agent settings",
|
||||||
@@ -396,6 +395,9 @@
|
|||||||
"manualListHint": "New tasks in this list start out manual: no queueing, running or refining, and automation skips them. You can still open a hand-driven session.",
|
"manualListHint": "New tasks in this list start out manual: no queueing, running or refining, and automation skips them. You can still open a hand-driven session.",
|
||||||
"findingsTracked": "Commit the .claudedo findings folder",
|
"findingsTracked": "Commit the .claudedo findings folder",
|
||||||
"findingsTrackedHint": "Off: the folder stays out of git via .git/info/exclude. On: findings travel with the repo.",
|
"findingsTrackedHint": "Off: the folder stays out of git via .git/info/exclude. On: findings travel with the repo.",
|
||||||
|
"sectionIcon": "ICON",
|
||||||
|
"icon": "List icon",
|
||||||
|
"iconHint": "Shown next to the list name in the sidebar.",
|
||||||
"sectionAgent": "AGENT",
|
"sectionAgent": "AGENT",
|
||||||
"resetAgentSettings": "Reset agent settings",
|
"resetAgentSettings": "Reset agent settings",
|
||||||
"sectionVerify": "VERIFICATION",
|
"sectionVerify": "VERIFICATION",
|
||||||
|
|||||||
@@ -33,8 +33,9 @@
|
|||||||
<!-- All d-strings sourced from icons.jsx -->
|
<!-- All d-strings sourced from icons.jsx -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
|
|
||||||
<!-- Icon.Sun -->
|
<!-- Icon.Sun — filled disc + 8 rays. The old stroke-only version rendered as a bare dot in a
|
||||||
<StreamGeometry x:Key="Icon.Sun">M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z M12 3v2M12 19v2M3 12h2M19 12h2M5.5 5.5l1.4 1.4M17.1 17.1l1.4 1.4M5.5 18.5l1.4-1.4M17.1 6.9l1.4-1.4</StreamGeometry>
|
PathIcon (verified by rendering it); rays are kept clear of the disc so EvenOdd is safe. -->
|
||||||
|
<StreamGeometry x:Key="Icon.Sun">M7.5 12 C7.5 9.51 9.51 7.5 12 7.5 C14.49 7.5 16.5 9.51 16.5 12 C16.5 14.49 14.49 16.5 12 16.5 C9.51 16.5 7.5 14.49 7.5 12 Z M11 2 H13 V5.5 H11 Z M11 18.5 H13 V22 H11 Z M2 11 H5.5 V13 H2 Z M18.5 11 H22 V13 H18.5 Z M4.22 5.64 L5.64 4.22 L8.11 6.69 L6.69 8.11 Z M18.36 4.22 L19.78 5.64 L17.31 8.11 L15.89 6.69 Z M5.64 19.78 L4.22 18.36 L6.69 15.89 L8.11 17.31 Z M19.78 18.36 L18.36 19.78 L15.89 17.31 L17.31 15.89 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Activity (pulse waveform) — filled outline of the polyline; PathIcon fills, a stroke-only pulse renders as blobs -->
|
<!-- Icon.Activity (pulse waveform) — filled outline of the polyline; PathIcon fills, a stroke-only pulse renders as blobs -->
|
||||||
<StreamGeometry x:Key="Icon.Activity">M3,11 L6.28,11 L9,2.84 L12.86,14.43 L14.46,8.04 L17.41,11 L21,11 L21,13 L16.59,13 L15.54,11.96 L13.14,21.57 L9,9.16 L7.72,13 L3,13 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Activity">M3,11 L6.28,11 L9,2.84 L12.86,14.43 L14.46,8.04 L17.41,11 L21,11 L21,13 L16.59,13 L15.54,11.96 L13.14,21.57 L9,9.16 L7.72,13 L3,13 Z</StreamGeometry>
|
||||||
@@ -42,20 +43,23 @@
|
|||||||
<!-- Icon.Star -->
|
<!-- Icon.Star -->
|
||||||
<StreamGeometry x:Key="Icon.Star">M12 3.5l2.6 5.3 5.8.8-4.2 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Star">M12 3.5l2.6 5.3 5.8.8-4.2 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8-4.2-4.1 5.8-.8z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Calendar -->
|
<!-- Icon.Calendar — solid header band, hollow body, two binder posts and a date block.
|
||||||
<StreamGeometry x:Key="Icon.Calendar">M3.5 5a2 2 0 0 1 2-2h13a2 2 0 0 1 2 2v15a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z M3.5 10h17M8 3v4M16 3v4</StreamGeometry>
|
The old stroke version filled into a plain black square. -->
|
||||||
|
<StreamGeometry x:Key="Icon.Calendar">F0 M3 5 H21 V21 H3 Z M5 11 H19 V19 H5 Z M7 2 H9 V5 H7 Z M15 2 H17 V5 H15 Z M7.5 13 H10 V15.5 H7.5 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Eye -->
|
<!-- Icon.Eye -->
|
||||||
<StreamGeometry x:Key="Icon.Eye">M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Eye">M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Inbox -->
|
<!-- Icon.Inbox — tray frame with an arrow dropping into the upper compartment.
|
||||||
<StreamGeometry x:Key="Icon.Inbox">M3 13h5l1 2h6l1-2h5M3 13l3-8h12l3 8v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z</StreamGeometry>
|
The old stroke version filled into a solid slab. -->
|
||||||
|
<StreamGeometry x:Key="Icon.Inbox">F0 M3 5 H21 V19 H3 Z M5 7 H19 V12 H5 Z M5 14 H19 V17 H5 Z M11 7.6 H13 V9.4 H15 L12 12 L9 9.4 H11 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Folder -->
|
<!-- Icon.Folder -->
|
||||||
<StreamGeometry x:Key="Icon.Folder">M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Folder">M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Search -->
|
<!-- Icon.Search — hollow ring + handle. The old stroke version filled into a solid disc with
|
||||||
<StreamGeometry x:Key="Icon.Search">M11 4a7 7 0 1 0 0 14A7 7 0 0 0 11 4z M20 20l-3.5-3.5</StreamGeometry>
|
no handle at all (this one is also the magnifier in the lists search box). -->
|
||||||
|
<StreamGeometry x:Key="Icon.Search">F0 M3 10.5 C3 6.36 6.36 3 10.5 3 C14.64 3 18 6.36 18 10.5 C18 14.64 14.64 18 10.5 18 C6.36 18 3 14.64 3 10.5 Z M5.2 10.5 C5.2 7.57 7.57 5.2 10.5 5.2 C13.43 5.2 15.8 7.57 15.8 10.5 C15.8 13.43 13.43 15.8 10.5 15.8 C7.57 15.8 5.2 13.43 5.2 10.5 Z M14.88 16.58 L16.58 14.88 L22.05 20.35 L20.35 22.05 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Plus — filled cross (PathIcon fills, so a stroke-only plus renders invisible) -->
|
<!-- Icon.Plus — filled cross (PathIcon fills, so a stroke-only plus renders invisible) -->
|
||||||
<StreamGeometry x:Key="Icon.Plus">M10.6 5 H13.4 V10.6 H19 V13.4 H13.4 V19 H10.6 V13.4 H5 V10.6 H10.6 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Plus">M10.6 5 H13.4 V10.6 H19 V13.4 H13.4 V19 H10.6 V13.4 H5 V10.6 H10.6 Z</StreamGeometry>
|
||||||
@@ -87,8 +91,8 @@
|
|||||||
<!-- Icon.Stop — filled square (stop / interrupt) -->
|
<!-- Icon.Stop — filled square (stop / interrupt) -->
|
||||||
<StreamGeometry x:Key="Icon.Stop">M4 4 H20 V20 H4 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Stop">M4 4 H20 V20 H4 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.Check -->
|
<!-- Icon.Check — filled tick. The old stroke version filled into a solid wedge. -->
|
||||||
<StreamGeometry x:Key="Icon.Check">M4 12l5 5 11-11</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Check">M9.6 18.2 L3.4 12 L5.5 9.9 L9.6 14 L18.5 5.1 L20.6 7.2 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Icon.ArrowOut — filled arrow for "open external" button -->
|
<!-- Icon.ArrowOut — filled arrow for "open external" button -->
|
||||||
<StreamGeometry x:Key="Icon.ArrowOut">M13 4 H20 V11 H18 V7.4 L11.4 14 L10 12.6 L16.6 6 H13 Z M4 6 H10 V8 H6 V18 H16 V14 H18 V20 H4 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.ArrowOut">M13 4 H20 V11 H18 V7.4 L11.4 14 L10 12.6 L16.6 6 H13 Z M4 6 H10 V8 H6 V18 H16 V14 H18 V20 H4 Z</StreamGeometry>
|
||||||
@@ -115,6 +119,75 @@
|
|||||||
<!-- Icon.Skull — filled silhouette: rounded cranium + eye holes (EvenOdd) + jaw -->
|
<!-- Icon.Skull — filled silhouette: rounded cranium + eye holes (EvenOdd) + jaw -->
|
||||||
<StreamGeometry x:Key="Icon.Skull">F0 M12 2 C7 2 4 5.5 4 10 C4 13.5 6 16 8 17.5 L8 19 C8 20 8.9 21 10 21 L10 18.5 L14 18.5 L14 21 C15.1 21 16 20 16 19 L16 17.5 C18 16 20 13.5 20 10 C20 5.5 17 2 12 2 Z M8.5 8 L8.5 12 L11 12 L11 8 Z M13 8 L13 12 L15.5 12 L15.5 8 Z</StreamGeometry>
|
<StreamGeometry x:Key="Icon.Skull">F0 M12 2 C7 2 4 5.5 4 10 C4 13.5 6 16 8 17.5 L8 19 C8 20 8.9 21 10 21 L10 18.5 L14 18.5 L14 21 C15.1 21 16 20 16 19 L16 17.5 C18 16 20 13.5 20 10 C20 5.5 17 2 12 2 Z M8.5 8 L8.5 12 L11 12 L11 8 Z M13 8 L13 12 L15.5 12 L15.5 8 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
<!-- List icons — pickable in list settings → Icon tab. -->
|
||||||
|
<!-- All filled outlines (PathIcon fills; a stroke-only path is -->
|
||||||
|
<!-- invisible). Holes rely on the EvenOdd default; the two that -->
|
||||||
|
<!-- want overlapping subpaths to merge declare F1 explicitly. -->
|
||||||
|
<!-- ============================================================ -->
|
||||||
|
|
||||||
|
<!-- Icon.Box — carton: solid lid band, open body, seam -->
|
||||||
|
<StreamGeometry x:Key="Icon.Box">F0 M3 5 H21 V20 H3 Z M5 11 H19 V18 H5 Z M11 11 H13 V14 H11 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Truck — box body + cab + two wheels (F1: wheels overlap the body) -->
|
||||||
|
<StreamGeometry x:Key="Icon.Truck">F1 M2 6 H13.5 V16 H2 Z M13.5 9.5 H17.4 L21 13.1 V16 H13.5 Z M7 15.5 a2.5 2.5 0 1 0 0 5 a2.5 2.5 0 1 0 0-5 Z M17 15.5 a2.5 2.5 0 1 0 0 5 a2.5 2.5 0 1 0 0-5 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.MapPin — location pin with punched-out centre -->
|
||||||
|
<StreamGeometry x:Key="Icon.MapPin">F0 M12 2 C8.1 2 5 5.1 5 9 C5 14.2 12 22 12 22 C12 22 19 14.2 19 9 C19 5.1 15.9 2 12 2 Z M12 6.5 a2.5 2.5 0 1 0 0 5 a2.5 2.5 0 1 0 0-5 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Chart — three rising bars -->
|
||||||
|
<StreamGeometry x:Key="Icon.Chart">M4 13 H8 V20 H4 Z M10 8 H14 V20 H10 Z M16 4 H20 V20 H16 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Server — two rack units with punched-out status LEDs -->
|
||||||
|
<StreamGeometry x:Key="Icon.Server">F0 M3 4 H21 V10 H3 Z M3 14 H21 V20 H3 Z M5.5 6 H7.5 V8 H5.5 Z M5.5 16 H7.5 V18 H5.5 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Chip — CPU die with hollow core and eight pins -->
|
||||||
|
<StreamGeometry x:Key="Icon.Chip">F0 M7 7 H17 V17 H7 Z M9.5 9.5 H14.5 V14.5 H9.5 Z M9 3 H10.5 V6.5 H9 Z M13.5 3 H15 V6.5 H13.5 Z M9 17.5 H10.5 V21 H9 Z M13.5 17.5 H15 V21 H13.5 Z M3 9 H6.5 V10.5 H3 Z M3 13.5 H6.5 V15 H3 Z M17.5 9 H21 V10.5 H17.5 Z M17.5 13.5 H21 V15 H17.5 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Bolt — lightning bolt -->
|
||||||
|
<StreamGeometry x:Key="Icon.Bolt">M13 2 L4 14 H10 L9 22 L20 9 H13.6 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Rocket — hull with porthole hole + exhaust -->
|
||||||
|
<StreamGeometry x:Key="Icon.Rocket">F0 M12 2 C15.5 5 17.5 9.5 17.5 14 V17 L14.5 19 H9.5 L6.5 17 V14 C6.5 9.5 8.5 5 12 2 Z M12 7.5 a2.2 2.2 0 1 0 0 4.4 a2.2 2.2 0 1 0 0-4.4 Z M9.5 19.5 H14.5 L13 22.5 H11 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Bulb — bulb over two screw-base bands -->
|
||||||
|
<StreamGeometry x:Key="Icon.Bulb">F0 M12 2 C8.1 2 5 5.1 5 9 C5 11.6 6.4 13.9 8.5 15.1 V17 H15.5 V15.1 C17.6 13.9 19 11.6 19 9 C19 5.1 15.9 2 12 2 Z M8.5 18.2 H15.5 V19.8 H8.5 Z M9.8 20.9 H14.2 V22.3 H9.8 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Flask — Erlenmeyer flask, single closed outline -->
|
||||||
|
<StreamGeometry x:Key="Icon.Flask">M9 2 H15 V4 H14 V9.3 L19.4 19.4 A1.5 1.5 0 0 1 18.1 21.6 H5.9 A1.5 1.5 0 0 1 4.6 19.4 L10 9.3 V4 H9 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Shield — shield with a punched-out check -->
|
||||||
|
<StreamGeometry x:Key="Icon.Shield">F0 M12 2 L4 5 V11 C4 16 7.4 20.3 12 21.5 C16.6 20.3 20 16 20 11 V5 Z M11 16.2 L7.2 12.4 L8.9 10.7 L11 12.8 L15.4 8.4 L17.1 10.1 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Camera — body with viewfinder bump and punched-out lens -->
|
||||||
|
<StreamGeometry x:Key="Icon.Camera">F0 M9 3 H15 L16.5 5.5 H20 A2 2 0 0 1 22 7.5 V19 A2 2 0 0 1 20 21 H4 A2 2 0 0 1 2 19 V7.5 A2 2 0 0 1 4 5.5 H7.5 Z M12 9 a4.5 4.5 0 1 0 0 9 a4.5 4.5 0 1 0 0-9 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Image — frame with mountains and sun inside the cut-out -->
|
||||||
|
<StreamGeometry x:Key="Icon.Image">F0 M3 4 H21 V20 H3 Z M5 6 H19 V18 H5 Z M6.5 16.5 L10.5 11 L13.5 14.5 L15.5 12.5 L17.5 16.5 Z M8 8 a1.6 1.6 0 1 0 0 3.2 a1.6 1.6 0 1 0 0-3.2 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Barcode — six bars of varying width -->
|
||||||
|
<StreamGeometry x:Key="Icon.Barcode">M3 4 H5 V20 H3 Z M6.5 4 H7.5 V20 H6.5 Z M9 4 H11.5 V20 H9 Z M13 4 H14 V20 H13 Z M15.5 4 H17.5 V20 H15.5 Z M19 4 H21 V20 H19 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Mail — envelope: frame cut out, flap drawn back inside it -->
|
||||||
|
<StreamGeometry x:Key="Icon.Mail">F0 M2 5 H22 V19 H2 Z M4 7 H20 V17 H4 Z M4 7 L12 13.5 L20 7 L20 8.7 L12 15.2 L4 8.7 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Terminal — console frame with prompt chevron and caret -->
|
||||||
|
<StreamGeometry x:Key="Icon.Terminal">F0 M2 4 H22 V20 H2 Z M4 6 H20 V18 H4 Z M6 8.4 L7.4 7 L11.4 11 L7.4 15 L6 13.6 L8.6 11 Z M12.5 13.4 H17 V15.2 H12.5 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Code — angle brackets around a slash -->
|
||||||
|
<StreamGeometry x:Key="Icon.Code">M8.6 5.4 L10 6.8 L5.8 11 L10 15.2 L8.6 16.6 L3 11 Z M15.4 5.4 L21 11 L15.4 16.6 L14 15.2 L18.2 11 L14 6.8 Z M13.6 3.4 L15.4 3.9 L10.4 20.6 L8.6 20.1 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Database — cylinder with the top ellipse punched out. Béziers, not arcs: an arc
|
||||||
|
spanning exactly its own diameter degenerates to a straight line here (measured). -->
|
||||||
|
<StreamGeometry x:Key="Icon.Database">F0 M5.3 5.2 C5.3 3.43 8.3 2 12 2 C15.7 2 18.7 3.43 18.7 5.2 V18.8 C18.7 20.57 15.7 22 12 22 C8.3 22 5.3 20.57 5.3 18.8 Z M5.3 5.2 C5.3 3.43 8.3 2 12 2 C15.7 2 18.7 3.43 18.7 5.2 C18.7 6.97 15.7 8.4 12 8.4 C8.3 8.4 5.3 6.97 5.3 5.2 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Wand — wand shaft plus three sparkles (kept clear of the shaft) -->
|
||||||
|
<StreamGeometry x:Key="Icon.Wand">M3.3 19.3 L13.3 9.3 L14.7 10.7 L4.7 20.7 Z M18 2.5 L19.1 5.9 L22.5 7 L19.1 8.1 L18 11.5 L16.9 8.1 L13.5 7 L16.9 5.9 Z M6 3 L6.7 4.8 L8.5 5.5 L6.7 6.2 L6 8 L5.3 6.2 L3.5 5.5 L5.3 4.8 Z M19.5 15 L20.2 16.8 L22 17.5 L20.2 18.2 L19.5 20 L18.8 18.2 L17 17.5 L18.8 16.8 Z</StreamGeometry>
|
||||||
|
|
||||||
|
<!-- Icon.Clock — ring with hands; the hands only touch at x=12.8, never overlap (EvenOdd).
|
||||||
|
Béziers, not arcs: see Icon.Database. -->
|
||||||
|
<StreamGeometry x:Key="Icon.Clock">F0 M2 12 C2 6.48 6.48 2 12 2 C17.52 2 22 6.48 22 12 C22 17.52 17.52 22 12 22 C6.48 22 2 17.52 2 12 Z M4 12 C4 7.58 7.58 4 12 4 C16.42 4 20 7.58 20 12 C20 16.42 16.42 20 12 20 C7.58 20 4 16.42 4 12 Z M11.2 6.5 H12.8 V12.8 H11.2 Z M12.8 11.2 H16.5 V12.8 H12.8 Z</StreamGeometry>
|
||||||
|
|
||||||
<!-- Badge brushes -->
|
<!-- Badge brushes -->
|
||||||
<SolidColorBrush x:Key="DraftBadgeBrush" Color="{StaticResource TextMuteColor}"/>
|
<SolidColorBrush x:Key="DraftBadgeBrush" Color="{StaticResource TextMuteColor}"/>
|
||||||
<SolidColorBrush x:Key="PlanningBadgeBrush" Color="{StaticResource PeatColor}"/>
|
<SolidColorBrush x:Key="PlanningBadgeBrush" Color="{StaticResource PeatColor}"/>
|
||||||
@@ -789,6 +862,11 @@
|
|||||||
<Setter Property="Background" Value="{StaticResource AccentSoftBrush}" />
|
<Setter Property="Background" Value="{StaticResource AccentSoftBrush}" />
|
||||||
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
|
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- Resting icon colour. Must live here, not inline on the PathIcon: a local value outranks
|
||||||
|
every style, so an inline Foreground makes the .active accent below unreachable. -->
|
||||||
|
<Style Selector="Border.list-item PathIcon.list-icon">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource TextMuteBrush}" />
|
||||||
|
</Style>
|
||||||
<!-- Active item text / icon colors -->
|
<!-- Active item text / icon colors -->
|
||||||
<Style Selector="Border.list-item.active TextBlock.list-label">
|
<Style Selector="Border.list-item.active TextBlock.list-label">
|
||||||
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
private bool _suppressTitleSave;
|
private bool _suppressTitleSave;
|
||||||
private CancellationTokenSource? _titleSaveCts;
|
private CancellationTokenSource? _titleSaveCts;
|
||||||
|
|
||||||
// Set by shell so CloseDetailCommand can clear SelectedTask
|
// Set by shell so deleting a task can clear SelectedTask
|
||||||
public Action? CloseDetail { get; set; }
|
public Action? CloseDetail { get; set; }
|
||||||
|
|
||||||
// Set by shell so DeleteTaskCommand can remove from list
|
// Set by shell so DeleteTaskCommand can remove from list
|
||||||
@@ -1008,9 +1008,6 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private void CloseDetails() => CloseDetail?.Invoke();
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async System.Threading.Tasks.Task ToggleStarAsync()
|
private async System.Threading.Tasks.Task ToggleStarAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ public sealed partial class ListNavItemViewModel : ViewModelBase
|
|||||||
// Set while a dragged task hovers over this row as a move target — distinct from
|
// Set while a dragged task hovers over this row as a move target — distinct from
|
||||||
// DropHintAbove/Below, which mark an insertion point for list reordering.
|
// DropHintAbove/Below, which mark an insertion point for list reordering.
|
||||||
[ObservableProperty] private bool _isTaskDropTarget;
|
[ObservableProperty] private bool _isTaskDropTarget;
|
||||||
public string? IconKey { get; init; }
|
// Settable (not init) so a list-settings icon change refreshes the row in place.
|
||||||
public string? DotColorKey { get; init; }
|
[ObservableProperty] private string? _iconKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
if (row is null || Dialogs is null || _services is null) return;
|
if (row is null || Dialogs is null || _services is null) return;
|
||||||
var rawId = row.Id.StartsWith("user:", StringComparison.Ordinal) ? row.Id["user:".Length..] : row.Id;
|
var rawId = row.Id.StartsWith("user:", StringComparison.Ordinal) ? row.Id["user:".Length..] : row.Id;
|
||||||
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
||||||
await vm.LoadAsync(rawId, row.Name, row.WorkingDir, row.DefaultCommitType, row.IsManual, row.FindingsTracked);
|
await vm.LoadAsync(rawId, row.Name, row.WorkingDir, row.DefaultCommitType, row.IsManual, row.FindingsTracked, row.IconKey);
|
||||||
await Dialogs.ShowListSettingsAsync(vm);
|
await Dialogs.ShowListSettingsAsync(vm);
|
||||||
if (vm.Deleted) await LoadAsync();
|
if (vm.Deleted) await LoadAsync();
|
||||||
else await RefreshRowAsync(row.Id);
|
else await RefreshRowAsync(row.Id);
|
||||||
@@ -293,8 +293,6 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
await using var ctx = await _dbFactory.CreateDbContextAsync(ct);
|
await using var ctx = await _dbFactory.CreateDbContextAsync(ct);
|
||||||
var lists = new ListRepository(ctx);
|
var lists = new ListRepository(ctx);
|
||||||
var seedNames = new HashSet<string>(new[] { "My Day", "Important", "Planned" });
|
var seedNames = new HashSet<string>(new[] { "My Day", "Important", "Planned" });
|
||||||
var dotColors = new[] { "Moss", "Peat", "Sage" };
|
|
||||||
int idx = 0;
|
|
||||||
foreach (var l in await lists.GetAllAsync(ct))
|
foreach (var l in await lists.GetAllAsync(ct))
|
||||||
{
|
{
|
||||||
if (seedNames.Contains(l.Name)) continue;
|
if (seedNames.Contains(l.Name)) continue;
|
||||||
@@ -304,8 +302,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
Id = $"user:{l.Id}",
|
Id = $"user:{l.Id}",
|
||||||
Name = l.Name,
|
Name = l.Name,
|
||||||
Kind = ListKind.User,
|
Kind = ListKind.User,
|
||||||
IconKey = "Folder",
|
IconKey = l.Icon ?? "Folder",
|
||||||
DotColorKey = dotColors[idx % dotColors.Length],
|
|
||||||
WorkingDir = l.WorkingDir,
|
WorkingDir = l.WorkingDir,
|
||||||
DefaultCommitType = l.DefaultCommitType,
|
DefaultCommitType = l.DefaultCommitType,
|
||||||
IsManual = l.IsManual,
|
IsManual = l.IsManual,
|
||||||
@@ -314,7 +311,6 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
};
|
};
|
||||||
Items.Add(item);
|
Items.Add(item);
|
||||||
UserLists.Add(item);
|
UserLists.Add(item);
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
@@ -395,7 +391,6 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
Name = entity.Name,
|
Name = entity.Name,
|
||||||
Kind = ListKind.User,
|
Kind = ListKind.User,
|
||||||
IconKey = "Folder",
|
IconKey = "Folder",
|
||||||
DotColorKey = "Moss",
|
|
||||||
WorkingDir = entity.WorkingDir,
|
WorkingDir = entity.WorkingDir,
|
||||||
DefaultCommitType = entity.DefaultCommitType,
|
DefaultCommitType = entity.DefaultCommitType,
|
||||||
};
|
};
|
||||||
@@ -407,7 +402,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
if (Dialogs is not null && _services is not null)
|
if (Dialogs is not null && _services is not null)
|
||||||
{
|
{
|
||||||
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
var vm = _services.GetRequiredService<ListSettingsModalViewModel>();
|
||||||
await vm.LoadAsync(entity.Id, entity.Name, entity.WorkingDir, entity.DefaultCommitType, entity.IsManual, entity.FindingsTracked);
|
await vm.LoadAsync(entity.Id, entity.Name, entity.WorkingDir, entity.DefaultCommitType, entity.IsManual, entity.FindingsTracked, entity.Icon);
|
||||||
await Dialogs.ShowListSettingsAsync(vm);
|
await Dialogs.ShowListSettingsAsync(vm);
|
||||||
if (vm.Deleted) await LoadAsync();
|
if (vm.Deleted) await LoadAsync();
|
||||||
else await RefreshRowAsync(item.Id);
|
else await RefreshRowAsync(item.Id);
|
||||||
@@ -507,6 +502,7 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
row.DefaultCommitType = entity.DefaultCommitType;
|
row.DefaultCommitType = entity.DefaultCommitType;
|
||||||
row.IsManual = entity.IsManual;
|
row.IsManual = entity.IsManual;
|
||||||
row.FindingsTracked = entity.FindingsTracked;
|
row.FindingsTracked = entity.FindingsTracked;
|
||||||
|
row.IconKey = entity.Icon ?? "Folder";
|
||||||
row.HasTicketProject = hasTicketProject;
|
row.HasTicketProject = hasTicketProject;
|
||||||
RecomputeHasNoLinkedRepo();
|
RecomputeHasNoLinkedRepo();
|
||||||
}
|
}
|
||||||
@@ -547,14 +543,12 @@ public sealed partial class ListsIslandViewModel : ViewModelBase, IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task AddRowAsync(ListRepository lists, ListEntity entity, bool hasTicketProject = false)
|
private async Task AddRowAsync(ListRepository lists, ListEntity entity, bool hasTicketProject = false)
|
||||||
{
|
{
|
||||||
var dotColors = new[] { "Moss", "Peat", "Sage" };
|
|
||||||
var item = new ListNavItemViewModel
|
var item = new ListNavItemViewModel
|
||||||
{
|
{
|
||||||
Id = $"user:{entity.Id}",
|
Id = $"user:{entity.Id}",
|
||||||
Name = entity.Name,
|
Name = entity.Name,
|
||||||
Kind = ListKind.User,
|
Kind = ListKind.User,
|
||||||
IconKey = "Folder",
|
IconKey = entity.Icon ?? "Folder",
|
||||||
DotColorKey = dotColors[UserLists.Count % dotColors.Length],
|
|
||||||
WorkingDir = entity.WorkingDir,
|
WorkingDir = entity.WorkingDir,
|
||||||
DefaultCommitType = entity.DefaultCommitType,
|
DefaultCommitType = entity.DefaultCommitType,
|
||||||
IsManual = entity.IsManual,
|
IsManual = entity.IsManual,
|
||||||
|
|||||||
@@ -42,12 +42,34 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
|||||||
// lands; a non-zero exit keeps the task out of Done instead of silently reporting merged.
|
// lands; a non-zero exit keeps the task out of Done instead of silently reporting merged.
|
||||||
[ObservableProperty] private string _verifyCommand = "";
|
[ObservableProperty] private string _verifyCommand = "";
|
||||||
// Dropdown hidden entirely when no ticket-system base URL is configured (Settings → Files tab).
|
// Dropdown hidden entirely when no ticket-system base URL is configured (Settings → Files tab).
|
||||||
|
// Icon key into the UI icon library (IconKeyConverter -> "Icon.<key>" StreamGeometry).
|
||||||
|
[ObservableProperty] private string _icon = DefaultIcon;
|
||||||
[ObservableProperty] private bool _ticketsAvailable;
|
[ObservableProperty] private bool _ticketsAvailable;
|
||||||
[ObservableProperty] private TicketProjectOption? _selectedTicketProject;
|
[ObservableProperty] private TicketProjectOption? _selectedTicketProject;
|
||||||
public ObservableCollection<TicketProjectOption> TicketProjects { get; } = new();
|
public ObservableCollection<TicketProjectOption> TicketProjects { get; } = new();
|
||||||
|
|
||||||
public ObservableCollection<string> CommitTypeOptions { get; } = new(CommitTypeRegistry.Types);
|
public ObservableCollection<string> CommitTypeOptions { get; } = new(CommitTypeRegistry.Types);
|
||||||
|
|
||||||
|
public const string DefaultIcon = "Folder";
|
||||||
|
|
||||||
|
// Curated subset of the Icon.* geometry library in IslandStyles.axaml — window chrome and
|
||||||
|
// pure stroke icons (PathIcon fills, so those render invisible) are deliberately left out.
|
||||||
|
// Grouped by theme so the picker grid reads in rows; every entry needs a matching
|
||||||
|
// "Icon.<key>" StreamGeometry or it renders as an empty slot.
|
||||||
|
public static readonly string[] IconOptions =
|
||||||
|
[
|
||||||
|
// general
|
||||||
|
"Folder", "Star", "Sun", "Calendar", "Clock", "Inbox", "Mail", "Text", "Search", "Grid",
|
||||||
|
// dev
|
||||||
|
"Code", "Terminal", "Database", "Server", "Chip", "Bolt", "Wand", "Flask", "Shield",
|
||||||
|
// status / flow
|
||||||
|
"Activity", "Eye", "Check", "Warning", "Chart", "Rocket", "Bulb", "Broom", "AgentSuggested", "Settings",
|
||||||
|
// things
|
||||||
|
"Box", "Truck", "MapPin", "Camera", "Image", "Barcode", "Skull",
|
||||||
|
];
|
||||||
|
|
||||||
|
public ObservableCollection<string> Icons { get; } = new(IconOptions);
|
||||||
|
|
||||||
// The shared agent-config editor (Model / MaxTurns / SystemPrompt / AgentFile),
|
// The shared agent-config editor (Model / MaxTurns / SystemPrompt / AgentFile),
|
||||||
// scoped to this list (list → global inheritance).
|
// scoped to this list (list → global inheritance).
|
||||||
public AgentConfigEditorViewModel Agent { get; }
|
public AgentConfigEditorViewModel Agent { get; }
|
||||||
@@ -68,12 +90,16 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
|||||||
string defaultCommitType,
|
string defaultCommitType,
|
||||||
bool isManual = false,
|
bool isManual = false,
|
||||||
bool findingsTracked = false,
|
bool findingsTracked = false,
|
||||||
|
string? icon = null,
|
||||||
CancellationToken ct = default)
|
CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
ListId = listId;
|
ListId = listId;
|
||||||
Name = name;
|
Name = name;
|
||||||
IsManual = isManual;
|
IsManual = isManual;
|
||||||
FindingsTracked = findingsTracked;
|
FindingsTracked = findingsTracked;
|
||||||
|
// An unknown/legacy key would leave the picker with no selection and silently reset the
|
||||||
|
// icon on the next save — fall back to the default instead.
|
||||||
|
Icon = IconOptions.Contains(icon) ? icon! : DefaultIcon;
|
||||||
WorkingDir = workingDir ?? "";
|
WorkingDir = workingDir ?? "";
|
||||||
DefaultCommitType = string.IsNullOrWhiteSpace(defaultCommitType) ? CommitTypeRegistry.DefaultType : defaultCommitType;
|
DefaultCommitType = string.IsNullOrWhiteSpace(defaultCommitType) ? CommitTypeRegistry.DefaultType : defaultCommitType;
|
||||||
|
|
||||||
@@ -111,7 +137,8 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
|
|||||||
string.IsNullOrWhiteSpace(WorkingDir) ? null : WorkingDir,
|
string.IsNullOrWhiteSpace(WorkingDir) ? null : WorkingDir,
|
||||||
DefaultCommitType,
|
DefaultCommitType,
|
||||||
IsManual,
|
IsManual,
|
||||||
FindingsTracked));
|
FindingsTracked,
|
||||||
|
Icon));
|
||||||
|
|
||||||
// Tri-state: dropdown never shown (no base URL) -> null, leave the stored link alone.
|
// Tri-state: dropdown never shown (no base URL) -> null, leave the stored link alone.
|
||||||
// Dropdown shown -> always an explicit value, 0 for "— none —" to actively clear it.
|
// Dropdown shown -> always an explicit value, 0 for "— none —" to actively clear it.
|
||||||
|
|||||||
@@ -10,12 +10,15 @@
|
|||||||
|
|
||||||
<!-- Column 0: id badge + editable title -->
|
<!-- Column 0: id badge + editable title -->
|
||||||
<StackPanel Grid.Column="0" Spacing="0">
|
<StackPanel Grid.Column="0" Spacing="0">
|
||||||
<TextBlock Classes="meta"
|
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,0,0,4">
|
||||||
Text="{Binding TaskIdBadge}"
|
<TextBlock Classes="meta"
|
||||||
Margin="0,0,0,4"
|
Text="{Binding TaskIdBadge}"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
ToolTip.Tip="{loc:Tr details.copyTaskIdTip}"
|
ToolTip.Tip="{loc:Tr details.copyTaskIdTip}"
|
||||||
Tapped="OnTaskIdTapped"/>
|
Tapped="OnTaskIdTapped"/>
|
||||||
|
<!-- created-at moved up from the removed metadata footer -->
|
||||||
|
<TextBlock Classes="meta" Text="{Binding Task.CreatedAtFormatted}"/>
|
||||||
|
</StackPanel>
|
||||||
<TextBox Text="{Binding EditableTitle, Mode=TwoWay}"
|
<TextBox Text="{Binding EditableTitle, Mode=TwoWay}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
|
|||||||
@@ -11,27 +11,6 @@
|
|||||||
<Panel>
|
<Panel>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
|
||||||
<!-- ── Metadata footer (sticky bottom) — created-at + close — task detail only ── -->
|
|
||||||
<Border DockPanel.Dock="Bottom"
|
|
||||||
IsVisible="{Binding IsTaskDetailVisible}"
|
|
||||||
BorderBrush="{DynamicResource LineBrush}"
|
|
||||||
BorderThickness="0,1,0,0"
|
|
||||||
Padding="14,8">
|
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
|
||||||
<TextBlock Grid.Column="0"
|
|
||||||
Classes="meta"
|
|
||||||
Text="{Binding Task.CreatedAtFormatted}"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"/>
|
|
||||||
<Button Grid.Column="1" Classes="icon-btn"
|
|
||||||
Command="{Binding CloseDetailsCommand}"
|
|
||||||
ToolTip.Tip="{loc:Tr details.closeTip}"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<PathIcon Data="{StaticResource Icon.X}" Width="14" Height="14"/>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- ── Header (sticky top): id · title · trash/skull · gear — task detail only ── -->
|
<!-- ── Header (sticky top): id · title · trash/skull · gear — task detail only ── -->
|
||||||
<Border DockPanel.Dock="Top" Classes="island-header"
|
<Border DockPanel.Dock="Top" Classes="island-header"
|
||||||
IsVisible="{Binding IsTaskDetailVisible}">
|
IsVisible="{Binding IsTaskDetailVisible}">
|
||||||
|
|||||||
@@ -103,7 +103,6 @@
|
|||||||
<PathIcon Grid.Column="0" Classes="list-icon"
|
<PathIcon Grid.Column="0" Classes="list-icon"
|
||||||
Width="14" Height="14"
|
Width="14" Height="14"
|
||||||
Data="{Binding IconKey, Converter={StaticResource IconKey}}"
|
Data="{Binding IconKey, Converter={StaticResource IconKey}}"
|
||||||
Foreground="{DynamicResource TextMuteBrush}"
|
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<TextBlock Grid.Column="1" Classes="list-label"
|
<TextBlock Grid.Column="1" Classes="list-label"
|
||||||
@@ -177,11 +176,11 @@
|
|||||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||||
Margin="-8,0,0,0"/>
|
Margin="-8,0,0,0"/>
|
||||||
</Border>
|
</Border>
|
||||||
<!-- Color dot (6px circle, color from DotColorKey) -->
|
<!-- Icon (list-settings → Icon tab; "Folder" when unset) -->
|
||||||
<Ellipse Grid.Column="0"
|
<PathIcon Grid.Column="0" Classes="list-icon"
|
||||||
Width="6" Height="6"
|
Width="14" Height="14"
|
||||||
Fill="{Binding DotColorKey, Converter={StaticResource DotBrush}}"
|
Data="{Binding IconKey, Converter={StaticResource IconKey}}"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<TextBlock Grid.Column="1" Classes="list-label"
|
<TextBlock Grid.Column="1" Classes="list-label"
|
||||||
Text="{Binding Name}"
|
Text="{Binding Name}"
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
Background="Transparent" Margin="12,16,8,8"
|
Background="Transparent" Margin="12,16,8,8"
|
||||||
VerticalAlignment="Top">
|
VerticalAlignment="Top">
|
||||||
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionGeneral}"/>
|
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionGeneral}"/>
|
||||||
|
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionIcon}"/>
|
||||||
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionAgent}"/>
|
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionAgent}"/>
|
||||||
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionVerify}"/>
|
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionVerify}"/>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
@@ -113,6 +114,35 @@
|
|||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
<!-- ICON -->
|
||||||
|
<TabItem Header="{loc:Tr modals.listSettings.sectionIcon}">
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" Margin="0,8,0,0">
|
||||||
|
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.icon}"/>
|
||||||
|
<ListBox ItemsSource="{Binding Icons}"
|
||||||
|
SelectedItem="{Binding Icon, Mode=TwoWay}"
|
||||||
|
Background="Transparent" BorderThickness="0"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<ListBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel/>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListBox.ItemsPanel>
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<!-- No Foreground here on purpose: the icon inherits the container's, so the
|
||||||
|
selected/hover states of ListBoxItem reach it (see Ui/CLAUDE.md). -->
|
||||||
|
<PathIcon Width="20" Height="20" Margin="6"
|
||||||
|
Data="{Binding Converter={StaticResource IconKey}}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
<TextBlock Text="{loc:Tr modals.listSettings.iconHint}"
|
||||||
|
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
<!-- AGENT -->
|
<!-- AGENT -->
|
||||||
<TabItem Header="{loc:Tr modals.listSettings.sectionAgent}">
|
<TabItem Header="{loc:Tr modals.listSettings.sectionAgent}">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
|
|||||||
@@ -543,6 +543,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
|
|||||||
entity.DefaultCommitType = string.IsNullOrWhiteSpace(dto.DefaultCommitType) ? CommitTypeRegistry.DefaultType : dto.DefaultCommitType;
|
entity.DefaultCommitType = string.IsNullOrWhiteSpace(dto.DefaultCommitType) ? CommitTypeRegistry.DefaultType : dto.DefaultCommitType;
|
||||||
entity.IsManual = dto.IsManual;
|
entity.IsManual = dto.IsManual;
|
||||||
entity.FindingsTracked = dto.FindingsTracked;
|
entity.FindingsTracked = dto.FindingsTracked;
|
||||||
|
entity.Icon = string.IsNullOrWhiteSpace(dto.Icon) ? null : dto.Icon;
|
||||||
await repo.UpdateAsync(entity);
|
await repo.UpdateAsync(entity);
|
||||||
|
|
||||||
await _broadcaster.ListUpdated(dto.Id);
|
await _broadcaster.ListUpdated(dto.Id);
|
||||||
|
|||||||
Reference in New Issue
Block a user