feat: assign and delete inbox artifacts
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type InboxNodeDTO struct {
|
||||
NodeDTO
|
||||
CaptureKind string `json:"captureKind"`
|
||||
@@ -32,6 +34,42 @@ func (a *App) ListInboxNodes() ([]InboxNodeDTO, error) {
|
||||
return dtos, nil
|
||||
}
|
||||
|
||||
func (a *App) AssignInboxNode(nodeID, targetParentID string) (*NodeDTO, error) {
|
||||
if err := a.requireVault(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !a.isInboxCaptureNode(nodeID) {
|
||||
return nil, fmt.Errorf("node is not an inbox artifact")
|
||||
}
|
||||
if targetParentID == "" {
|
||||
return nil, fmt.Errorf("target parent is required")
|
||||
}
|
||||
if err := a.MoveNode(nodeID, targetParentID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := a.clearCaptureMeta(nodeID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto, err := a.GetNodeDetail(nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dto, nil
|
||||
}
|
||||
|
||||
func (a *App) DeleteInboxNode(nodeID string) error {
|
||||
if err := a.requireVault(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !a.isInboxCaptureNode(nodeID) {
|
||||
return fmt.Errorf("node is not an inbox artifact")
|
||||
}
|
||||
if err := a.DeleteNode(nodeID); err != nil {
|
||||
return err
|
||||
}
|
||||
return a.clearCaptureMeta(nodeID)
|
||||
}
|
||||
|
||||
func (a *App) filterInboxCaptureNodes(list []NodeDTO) []NodeDTO {
|
||||
out := make([]NodeDTO, 0, len(list))
|
||||
for _, item := range list {
|
||||
@@ -46,3 +84,8 @@ func (a *App) isInboxCaptureNode(nodeID string) bool {
|
||||
v, ok, err := a.nodes.MetaGet(nodeID, "capture.inbox")
|
||||
return err == nil && ok && v == "true"
|
||||
}
|
||||
|
||||
func (a *App) clearCaptureMeta(nodeID string) error {
|
||||
_, err := a.db.Exec(`DELETE FROM node_meta WHERE node_id = ? AND key LIKE 'capture.%'`, nodeID)
|
||||
return err
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,8 +16,8 @@
|
||||
background: #13131f;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/main-D-CBbIRx.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BgORPqqS.css">
|
||||
<script type="module" crossorigin src="/assets/main-B7pwitR5.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-CnGHmBj4.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"verstak/internal/core/nodes"
|
||||
)
|
||||
|
||||
func TestListInboxNodesReturnsOnlyCapturedArtifacts(t *testing.T) {
|
||||
app, _ := setupTestApp(t)
|
||||
@@ -76,3 +81,72 @@ func TestListInboxNodesReturnsOnlyCapturedArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssignInboxNodeMovesArtifactIntoCase(t *testing.T) {
|
||||
app, _ := setupTestApp(t)
|
||||
|
||||
parent, err := app.CreateNodeFromTemplate("", "Target Case", "folder.default")
|
||||
if err != nil {
|
||||
t.Fatalf("create parent: %v", err)
|
||||
}
|
||||
captured, err := app.CaptureText("Captured task material")
|
||||
if err != nil {
|
||||
t.Fatalf("CaptureText: %v", err)
|
||||
}
|
||||
|
||||
moved, err := app.AssignInboxNode(captured.ID, parent.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("AssignInboxNode: %v", err)
|
||||
}
|
||||
if moved.ParentID == nil || *moved.ParentID != parent.ID {
|
||||
t.Fatalf("ParentID = %v, want %q", moved.ParentID, parent.ID)
|
||||
}
|
||||
|
||||
inbox, err := app.ListInboxNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("ListInboxNodes: %v", err)
|
||||
}
|
||||
for _, item := range inbox {
|
||||
if item.ID == captured.ID {
|
||||
t.Fatal("assigned artifact should leave inbox")
|
||||
}
|
||||
}
|
||||
notes, err := app.ListNotes(parent.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListNotes: %v", err)
|
||||
}
|
||||
var found bool
|
||||
for _, note := range notes {
|
||||
if note.ID == captured.ID {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("assigned text artifact missing from target case notes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteInboxNodeRemovesArtifactFromInbox(t *testing.T) {
|
||||
app, _ := setupTestApp(t)
|
||||
|
||||
captured, err := app.CaptureText("Delete this captured material")
|
||||
if err != nil {
|
||||
t.Fatalf("CaptureText: %v", err)
|
||||
}
|
||||
if err := app.DeleteInboxNode(captured.ID); err != nil {
|
||||
t.Fatalf("DeleteInboxNode: %v", err)
|
||||
}
|
||||
|
||||
inbox, err := app.ListInboxNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("ListInboxNodes: %v", err)
|
||||
}
|
||||
for _, item := range inbox {
|
||||
if item.ID == captured.ID {
|
||||
t.Fatal("deleted artifact should leave inbox")
|
||||
}
|
||||
}
|
||||
if _, err := app.nodes.GetActive(captured.ID); !errors.Is(err, nodes.ErrNotFound) {
|
||||
t.Fatalf("GetActive err = %v, want ErrNotFound", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user