fix(workspace): extract replaces the branch in the editor, with undo
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m2s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m2s
The server only creates the new note and returns the link; the editor swaps the branch for it as an ordinary own edit through the sync engine. No more clash with unsent typing (conflict copies), the link shows at once also with polling, and Strg+Z restores the branch. Undoing (toast or Strg+Z) puts the new note into the trash via POST /extract/undo. The sidebar gets the new note right away and opens its folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
02ce554c02
commit
362dd3b4c6
10 files changed
+163
-71
No files matched your search
@@ -92,16 +92,17 @@ func foreignLeaseIn(ids []string, a collab.Actor, leases collab.LeaseView) bool
|
||||
return false
|
||||
}
|
||||
|
||||
// ExtractBranch moves a bullet's children into a new note named after the bullet, in the same folder,
|
||||
// shared like the original; the bullet itself becomes a [[link]] to it. Returns the new note.
|
||||
func (s *Store) ExtractBranch(userID, docID, blockID string, a collab.Actor, leases collab.LeaseView) (*domain.Document, error) {
|
||||
// ExtractBranch creates a new note from a bullet's children, named after the bullet, in the same folder
|
||||
// and shared like the original. The original note is not changed here: the editor replaces the branch
|
||||
// by the returned link itself, as an ordinary own edit (no clash with unsent typing, undo works).
|
||||
func (s *Store) ExtractBranch(userID, docID, blockID string, a collab.Actor, leases collab.LeaseView) (*domain.Document, string, error) {
|
||||
source, err := s.GetDocumentByID(userID, docID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
state, err := s.readCollabDoc(docID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
flat := state.Flatten()
|
||||
start := -1
|
||||
@@ -112,7 +113,7 @@ func (s *Store) ExtractBranch(userID, docID, blockID string, a collab.Actor, lea
|
||||
}
|
||||
}
|
||||
if start < 0 {
|
||||
return nil, ErrBlockNotFound
|
||||
return nil, "", ErrBlockNotFound
|
||||
}
|
||||
root := flat[start]
|
||||
var children []domain.DocumentBlock
|
||||
@@ -122,37 +123,36 @@ func (s *Store) ExtractBranch(userID, docID, blockID string, a collab.Actor, lea
|
||||
ids = append(ids, flat[i].ID)
|
||||
}
|
||||
if foreignLeaseIn(ids, a, leases) {
|
||||
return nil, ErrBranchLocked
|
||||
return nil, "", ErrBranchLocked
|
||||
}
|
||||
|
||||
base, tags := branchTitle(root.Content)
|
||||
title := s.uniqueTitle(userID, base)
|
||||
created, err := s.CreateDocument(userID, "", title, "📄", source.FolderPath, children, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
s.copyShares(userID, source, created.ID)
|
||||
|
||||
link := "[[" + title + "]]"
|
||||
if tags != "" {
|
||||
link += " " + tags
|
||||
}
|
||||
_, _, err = s.applyDocChange(docID, a, leases, func(d *collab.Doc) []collab.Op {
|
||||
b, ok := d.Blocks[blockID]
|
||||
if !ok || b.Deleted {
|
||||
return nil
|
||||
}
|
||||
ops := []collab.Op{{OpID: domain.NewID("op"), Kind: collab.OpSetContent, BlockID: blockID, BaseVersion: b.Version, Content: &link}}
|
||||
for _, c := range d.Children(blockID) {
|
||||
ops = append(ops, collab.Op{OpID: domain.NewID("op"), Kind: collab.OpDelete, BlockID: c.ID})
|
||||
}
|
||||
return ops
|
||||
})
|
||||
return created, link, nil
|
||||
}
|
||||
|
||||
// UndoExtract puts a note created by ExtractBranch into the trash (only its creator may).
|
||||
func (s *Store) UndoExtract(userID, docID string) error {
|
||||
doc, err := s.GetDocumentByID(userID, docID)
|
||||
if err != nil {
|
||||
_ = s.hardDeleteDocument(created.ID)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
return created, nil
|
||||
if !doc.IsOwner {
|
||||
return ErrMergeNotOwner
|
||||
}
|
||||
if doc.IsArchived {
|
||||
return nil
|
||||
}
|
||||
return s.trashDocument(userID, docID)
|
||||
}
|
||||
|
||||
// copyShares gives the new note the direct and team shares of the source; when someone else owns the
|
||||
|
||||
Reference in new issue
Block a user