1、将排序做到border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted里,无需单独做个button 2、指定重命名使用ICO,无需使用菜单
This commit is contained in:
1 parent
48e85b33d6
commit
86eb67ea0a
15 files changed
+957
-20
No files matched your search
+44
-3
@@ -32,6 +32,7 @@ type Task struct {
|
||||
Name string `json:"name"` // 可选任务名称;空=未命名
|
||||
CategoryID *int64 `json:"category_id,omitempty"`
|
||||
CategoryName string `json:"category_name,omitempty"`
|
||||
PinnedAt int64 `json:"pinned_at,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Goal string `json:"goal"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
@@ -77,6 +78,8 @@ type Task struct {
|
||||
// updateLifecycle instead of reading or writing the corresponding Task fields
|
||||
// directly after the task has been published by Manager.
|
||||
type taskLifecycleState struct {
|
||||
Name string
|
||||
PinnedAt int64
|
||||
Status string
|
||||
Paused bool
|
||||
Queued bool
|
||||
@@ -102,6 +105,8 @@ func (t *Task) lifecycleSnapshot() taskLifecycleState {
|
||||
|
||||
func (t *Task) lifecycleSnapshotLocked() taskLifecycleState {
|
||||
return taskLifecycleState{
|
||||
Name: t.Name,
|
||||
PinnedAt: t.PinnedAt,
|
||||
Status: t.Status,
|
||||
Paused: t.Paused,
|
||||
Queued: t.Queued,
|
||||
@@ -124,6 +129,8 @@ func (t *Task) updateLifecycle(update func(*taskLifecycleState)) {
|
||||
t.lifecycleMu.Lock()
|
||||
state := t.lifecycleSnapshotLocked()
|
||||
update(&state)
|
||||
t.Name = state.Name
|
||||
t.PinnedAt = state.PinnedAt
|
||||
t.Status = state.Status
|
||||
t.Paused = state.Paused
|
||||
t.Queued = state.Queued
|
||||
@@ -698,6 +705,7 @@ func taskFromPG(pt *pgdb.Task, store *pgdb.ExplorationStore, ic *intercept.Inter
|
||||
ID: strconv.FormatInt(pt.ID, 10), ExpID: pt.ExplorationID,
|
||||
Name: pt.Name,
|
||||
CategoryID: cloneInt64Ptr(pt.CategoryID), CategoryName: pt.CategoryName,
|
||||
PinnedAt: unixOrZero(pt.PinnedAt),
|
||||
Description: pt.Description, Goal: pt.Goal, CreatedAt: pt.CreatedAt.Unix(), Paused: pt.Paused, Queued: pt.Queued,
|
||||
QueuedAt: unixNanoOrZero(pt.QueuedAt), QueueMode: pt.QueueMode,
|
||||
CompletedAt: unixOrZero(pt.CompletedAt), Status: pt.Status, ParentRef: pt.ParentRef,
|
||||
@@ -714,6 +722,32 @@ func taskFromPG(pt *pgdb.Task, store *pgdb.ExplorationStore, ic *intercept.Inter
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateTaskMetadata changes list-only task metadata without interrupting any
|
||||
// planner, main-agent, or worker call.
|
||||
func (m *Manager) UpdateTaskMetadata(taskID string, patch pgdb.TaskPatch) (*Task, error) {
|
||||
m.taskStateMu.Lock()
|
||||
defer m.taskStateMu.Unlock()
|
||||
id, err := strconv.ParseInt(taskID, 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
updated, err := m.pg.UpdateTask(id, patch)
|
||||
if err != nil || updated == nil {
|
||||
return nil, err
|
||||
}
|
||||
m.mu.RLock()
|
||||
task := m.tasks[taskID]
|
||||
m.mu.RUnlock()
|
||||
if task == nil {
|
||||
return nil, nil
|
||||
}
|
||||
task.updateLifecycle(func(state *taskLifecycleState) {
|
||||
state.Name = updated.Name
|
||||
state.PinnedAt = unixOrZero(updated.PinnedAt)
|
||||
})
|
||||
return task, nil
|
||||
}
|
||||
|
||||
// CreateTask creates a task + its exploration and makes it active.
|
||||
// timeoutSeconds is the task-level wall-clock budget (0 = 不限时).
|
||||
func (m *Manager) CreateTask(description, goal string, llmProfileID *int64, timeoutSeconds, planHeartbeatSeconds int) (*Task, error) {
|
||||
@@ -1558,10 +1592,17 @@ func (m *Manager) List() []*Task {
|
||||
for _, t := range m.tasks {
|
||||
out = append(out, t)
|
||||
}
|
||||
// 按 id 降序(最新插入在最前)。m.tasks 是 map,遍历顺序随机,每次轮询都要重排;
|
||||
// 若按 CreatedAt 排,同一秒创建的任务时间戳相同,排序不稳定,会在列表里频繁换
|
||||
// 位置。id 由 BIGSERIAL 单调递增分配,唯一且稳定,顺序恒定。
|
||||
// 置顶任务优先,组内按置顶时间倒序;普通任务按 id 倒序。m.tasks 是 map,
|
||||
// 每次轮询都必须重排,id 则为同刻创建任务提供稳定且唯一的兜底顺序。
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
iState := out[i].lifecycleSnapshot()
|
||||
jState := out[j].lifecycleSnapshot()
|
||||
if (iState.PinnedAt > 0) != (jState.PinnedAt > 0) {
|
||||
return iState.PinnedAt > 0
|
||||
}
|
||||
if iState.PinnedAt != jState.PinnedAt {
|
||||
return iState.PinnedAt > jState.PinnedAt
|
||||
}
|
||||
ai, _ := strconv.ParseInt(out[i].ID, 10, 64)
|
||||
aj, _ := strconv.ParseInt(out[j].ID, 10, 64)
|
||||
return ai > aj
|
||||
|
||||
Reference in new issue
Block a user