Refactor Context Groups & Area Detection #4
							
								
								
									
										2
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@ -3,10 +3,12 @@
 | 
				
			|||||||
    "*.css": "tailwindcss"
 | 
					    "*.css": "tailwindcss"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "cSpell.words": [
 | 
					  "cSpell.words": [
 | 
				
			||||||
 | 
					    "consts",
 | 
				
			||||||
    "headlessui",
 | 
					    "headlessui",
 | 
				
			||||||
    "heroicons",
 | 
					    "heroicons",
 | 
				
			||||||
    "konva",
 | 
					    "konva",
 | 
				
			||||||
    "libretranslate",
 | 
					    "libretranslate",
 | 
				
			||||||
 | 
					    "tailwindcss",
 | 
				
			||||||
    "Tesseract",
 | 
					    "Tesseract",
 | 
				
			||||||
    "Textualize",
 | 
					    "Textualize",
 | 
				
			||||||
    "wailsjs"
 | 
					    "wailsjs"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										147
									
								
								core/ContextGroup/ContextGroupCollection.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								core/ContextGroup/ContextGroupCollection.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					package contextGroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"textualize/entities"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContextGroupCollection struct {
 | 
				
			||||||
 | 
						Groups []entities.LinkedAreaList
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var contextGroupCollectionInstance *ContextGroupCollection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetContextGroupCollection() *ContextGroupCollection {
 | 
				
			||||||
 | 
						if contextGroupCollectionInstance == nil {
 | 
				
			||||||
 | 
							contextGroupCollectionInstance = &ContextGroupCollection{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return contextGroupCollectionInstance
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetContextGroupCollection(collection ContextGroupCollection) *ContextGroupCollection {
 | 
				
			||||||
 | 
						contextGroupCollectionInstance = &collection
 | 
				
			||||||
 | 
						return contextGroupCollectionInstance
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetContextGroupCollectionBySerialized(serialized []entities.SerializedLinkedProcessedArea) *ContextGroupCollection {
 | 
				
			||||||
 | 
						newInstance := ContextGroupCollection{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						newInstance.Groups = append(newInstance.Groups, entities.DeserializeLinkedAreaList(serialized))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SetContextGroupCollection(newInstance)
 | 
				
			||||||
 | 
						return &newInstance
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) DoesGroupExistBetweenProcessedAreas(ancestorAreaId string, descendantAreaId string) bool {
 | 
				
			||||||
 | 
						ancestorGroup, _ := collection.FindGroupByLinkedProcessedAreaId(ancestorAreaId)
 | 
				
			||||||
 | 
						descendantGroup, _ := collection.FindGroupByLinkedProcessedAreaId(descendantAreaId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isAncestorInAnyInGroup := ancestorGroup != nil
 | 
				
			||||||
 | 
						isDescendantInAnyInGroup := descendantGroup != nil
 | 
				
			||||||
 | 
						areBothInAnyInGroup := isAncestorInAnyInGroup && isDescendantInAnyInGroup
 | 
				
			||||||
 | 
						areBothInSameGroup := false
 | 
				
			||||||
 | 
						if areBothInAnyInGroup {
 | 
				
			||||||
 | 
							areBothInSameGroup = ancestorGroup.Id == descendantGroup.Id
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return areBothInSameGroup
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) DisconnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool {
 | 
				
			||||||
 | 
						doesConnectionExist := collection.DoesGroupExistBetweenProcessedAreas(ancestorAreaId, descendantAreaId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !doesConnectionExist {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ancestorGroup, _ := collection.FindGroupByLinkedProcessedAreaId(ancestorAreaId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wasRemoved := false
 | 
				
			||||||
 | 
						for i, group := range collection.Groups {
 | 
				
			||||||
 | 
							if group.Id == ancestorGroup.Id {
 | 
				
			||||||
 | 
								collection.Groups = append(collection.Groups[:i], collection.Groups[i+1:]...)
 | 
				
			||||||
 | 
								wasRemoved = true
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return wasRemoved
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) FindGroupById(id string) (*entities.LinkedAreaList, error) {
 | 
				
			||||||
 | 
						found := false
 | 
				
			||||||
 | 
						var foundGroup *entities.LinkedAreaList = nil
 | 
				
			||||||
 | 
						for _, group := range collection.Groups {
 | 
				
			||||||
 | 
							if group.Id == id {
 | 
				
			||||||
 | 
								found = true
 | 
				
			||||||
 | 
								foundGroup = &group
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("ContextGroupCollection.FindGroupById: Group with id %s not found", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return foundGroup, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) FindGroupByLinkedProcessedAreaId(id string) (*entities.LinkedAreaList, error) {
 | 
				
			||||||
 | 
						found := false
 | 
				
			||||||
 | 
						var foundGroup *entities.LinkedAreaList = nil
 | 
				
			||||||
 | 
						for _, group := range collection.Groups {
 | 
				
			||||||
 | 
							for n := group.First(); n != nil && !found; n = n.GetNext() {
 | 
				
			||||||
 | 
								if n.Area.Id == id {
 | 
				
			||||||
 | 
									found = true
 | 
				
			||||||
 | 
									foundGroup = &group
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !found {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("ContextGroupCollection.FindGroupByLinkedProcessedAreaId: Group with LinkedProcessedArea.Id %s not found", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return foundGroup, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) ConnectProcessedAreas(ancestorNode entities.ProcessedArea, descendantNode entities.ProcessedArea) bool {
 | 
				
			||||||
 | 
						ancestorGroup, _ := collection.FindGroupByLinkedProcessedAreaId(ancestorNode.Id)
 | 
				
			||||||
 | 
						descendantGroup, _ := collection.FindGroupByLinkedProcessedAreaId(descendantNode.Id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isAncestorInAnyInGroup := ancestorGroup != nil
 | 
				
			||||||
 | 
						isDescendantInAnyInGroup := descendantGroup != nil
 | 
				
			||||||
 | 
						isEitherInAnyInGroup := isAncestorInAnyInGroup || isDescendantInAnyInGroup
 | 
				
			||||||
 | 
						areBothInAnyInGroup := isAncestorInAnyInGroup && isDescendantInAnyInGroup
 | 
				
			||||||
 | 
						areBothInSameGroup := false
 | 
				
			||||||
 | 
						if areBothInAnyInGroup {
 | 
				
			||||||
 | 
							areBothInSameGroup = ancestorGroup.Id == descendantGroup.Id
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if areBothInSameGroup {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !isEitherInAnyInGroup {
 | 
				
			||||||
 | 
							collection.createNewGroupAndConnectNodes(ancestorNode, descendantNode)
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isAncestorInAnyInGroup && !isDescendantInAnyInGroup {
 | 
				
			||||||
 | 
							ancestorGroup.InsertAfter(ancestorNode.Id, descendantNode)
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !isAncestorInAnyInGroup && isDescendantInAnyInGroup {
 | 
				
			||||||
 | 
							descendantGroup.InsertBefore(descendantNode.Id, ancestorNode)
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (collection *ContextGroupCollection) createNewGroupAndConnectNodes(ancestorNode entities.ProcessedArea, descendantNode entities.ProcessedArea) {
 | 
				
			||||||
 | 
						newGroup := entities.LinkedAreaList{
 | 
				
			||||||
 | 
							Id:         ancestorNode.Id,
 | 
				
			||||||
 | 
							DocumentId: ancestorNode.DocumentId,
 | 
				
			||||||
 | 
							Head:       &entities.LinkedProcessedArea{Area: ancestorNode},
 | 
				
			||||||
 | 
							Tail:       &entities.LinkedProcessedArea{Area: descendantNode},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						newGroup.Head.Next = newGroup.Tail
 | 
				
			||||||
 | 
						newGroup.Tail.Previous = newGroup.Head
 | 
				
			||||||
 | 
						collection.Groups = append(collection.Groups, newGroup)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,8 +3,6 @@ package entities
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/google/uuid"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type IndependentTranslatedWord struct {
 | 
					type IndependentTranslatedWord struct {
 | 
				
			||||||
@ -15,43 +13,57 @@ type IndependentTranslatedWord struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type LinkedProcessedArea struct {
 | 
					type LinkedProcessedArea struct {
 | 
				
			||||||
	Area     ProcessedArea
 | 
						Area     ProcessedArea
 | 
				
			||||||
	previous *LinkedProcessedArea
 | 
						Previous *LinkedProcessedArea
 | 
				
			||||||
	next     *LinkedProcessedArea
 | 
						Next     *LinkedProcessedArea
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SerializedLinkedProcessedArea struct {
 | 
				
			||||||
 | 
						AreaId     string `json:"areaId"`
 | 
				
			||||||
 | 
						PreviousId string `json:"previousId"`
 | 
				
			||||||
 | 
						NextId     string `json:"nextId"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ContextGroupCollection struct {
 | 
				
			||||||
 | 
						Groups []LinkedAreaList
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LinkedAreaList struct {
 | 
					type LinkedAreaList struct {
 | 
				
			||||||
	head *LinkedProcessedArea
 | 
						Id              string
 | 
				
			||||||
	tail *LinkedProcessedArea
 | 
						DocumentId      string
 | 
				
			||||||
 | 
						TranslationText string
 | 
				
			||||||
 | 
						Head            *LinkedProcessedArea
 | 
				
			||||||
 | 
						Tail            *LinkedProcessedArea
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *LinkedAreaList) First() *LinkedProcessedArea {
 | 
					func (l *LinkedAreaList) First() *LinkedProcessedArea {
 | 
				
			||||||
	return l.head
 | 
						return l.Head
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (linkedProcessedWord *LinkedProcessedArea) Next() *LinkedProcessedArea {
 | 
					func (linkedProcessedWord *LinkedProcessedArea) GetNext() *LinkedProcessedArea {
 | 
				
			||||||
	return linkedProcessedWord.next
 | 
						return linkedProcessedWord.Next
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (linkedProcessedWord *LinkedProcessedArea) Prev() *LinkedProcessedArea {
 | 
					func (linkedProcessedWord *LinkedProcessedArea) GetPrevious() *LinkedProcessedArea {
 | 
				
			||||||
	return linkedProcessedWord.previous
 | 
						return linkedProcessedWord.Previous
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create new node with value
 | 
					// Create new node with value
 | 
				
			||||||
func (l *LinkedAreaList) Push(processedArea ProcessedArea) *LinkedAreaList {
 | 
					func (l *LinkedAreaList) Push(processedArea ProcessedArea) *LinkedAreaList {
 | 
				
			||||||
	n := &LinkedProcessedArea{Area: processedArea}
 | 
						n := &LinkedProcessedArea{Area: processedArea}
 | 
				
			||||||
	if l.head == nil {
 | 
						if l.Head == nil {
 | 
				
			||||||
		l.head = n // First node
 | 
							l.Head = n // First node
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		l.tail.next = n     // Add after prev last node
 | 
							l.Tail.Next = n     // Add after prev last node
 | 
				
			||||||
		n.previous = l.tail // Link back to prev last node
 | 
							n.Previous = l.Tail // Link back to prev last node
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	l.tail = n // reset tail to newly added node
 | 
						l.Tail = n // reset tail to newly added node
 | 
				
			||||||
	return l
 | 
						return l
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *LinkedAreaList) Find(id string) *LinkedProcessedArea {
 | 
					func (l *LinkedAreaList) Find(id string) *LinkedProcessedArea {
 | 
				
			||||||
	found := false
 | 
						found := false
 | 
				
			||||||
	var ret *LinkedProcessedArea = nil
 | 
						var ret *LinkedProcessedArea = nil
 | 
				
			||||||
	for n := l.First(); n != nil && !found; n = n.Next() {
 | 
						for n := l.First(); n != nil && !found; n = n.GetNext() {
 | 
				
			||||||
		if n.Area.Id == id {
 | 
							if n.Area.Id == id {
 | 
				
			||||||
			found = true
 | 
								found = true
 | 
				
			||||||
			ret = n
 | 
								ret = n
 | 
				
			||||||
@ -59,16 +71,17 @@ func (l *LinkedAreaList) Find(id string) *LinkedProcessedArea {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return ret
 | 
						return ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (l *LinkedAreaList) Delete(id string) bool {
 | 
					func (l *LinkedAreaList) Delete(id string) bool {
 | 
				
			||||||
	success := false
 | 
						success := false
 | 
				
			||||||
	node2del := l.Find(id)
 | 
						node2del := l.Find(id)
 | 
				
			||||||
	if node2del != nil {
 | 
						if node2del != nil {
 | 
				
			||||||
		fmt.Println("Delete - FOUND: ", id)
 | 
							fmt.Println("Delete - FOUND: ", id)
 | 
				
			||||||
		prev_node := node2del.previous
 | 
							prev_node := node2del.Previous
 | 
				
			||||||
		next_node := node2del.next
 | 
							next_node := node2del.Next
 | 
				
			||||||
		// Remove this node
 | 
							// Remove this node
 | 
				
			||||||
		prev_node.next = node2del.next
 | 
							prev_node.Next = node2del.Next
 | 
				
			||||||
		next_node.previous = node2del.previous
 | 
							next_node.Previous = node2del.Previous
 | 
				
			||||||
		success = true
 | 
							success = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return success
 | 
						return success
 | 
				
			||||||
@ -78,86 +91,83 @@ var errEmpty = errors.New("ERROR - List is empty")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Pop last item from list
 | 
					// Pop last item from list
 | 
				
			||||||
func (l *LinkedAreaList) Pop() (processedArea ProcessedArea, err error) {
 | 
					func (l *LinkedAreaList) Pop() (processedArea ProcessedArea, err error) {
 | 
				
			||||||
	if l.tail == nil {
 | 
						if l.Tail == nil {
 | 
				
			||||||
		err = errEmpty
 | 
							err = errEmpty
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		processedArea = l.tail.Area
 | 
							processedArea = l.Tail.Area
 | 
				
			||||||
		l.tail = l.tail.previous
 | 
							l.Tail = l.Tail.Previous
 | 
				
			||||||
		if l.tail == nil {
 | 
							if l.Tail == nil {
 | 
				
			||||||
			l.head = nil
 | 
								l.Head = nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return processedArea, err
 | 
						return processedArea, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ContextGroup struct { // TODO: possibly remove this and expand the LinkedAreaList struct instead
 | 
					func (l *LinkedAreaList) InsertAfter(id string, processedArea ProcessedArea) bool {
 | 
				
			||||||
	Id              string
 | 
						found := false
 | 
				
			||||||
	DocumentId      string
 | 
						for n := l.First(); n != nil && !found; n = n.GetNext() {
 | 
				
			||||||
	LinkedAreaList  LinkedAreaList
 | 
							if n.Area.Id == id {
 | 
				
			||||||
	TranslationText string
 | 
								found = true
 | 
				
			||||||
}
 | 
								newNode := &LinkedProcessedArea{Area: processedArea}
 | 
				
			||||||
 | 
								newNode.Next = n.Next
 | 
				
			||||||
type ContextGroupCollection struct { // TODO: these methods should live in core not entitites
 | 
								newNode.Previous = n
 | 
				
			||||||
	Groups []ContextGroup
 | 
								n.Next = newNode
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var contextGroupCollectionInstance *ContextGroupCollection
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func GetContextGroupCollection() *ContextGroupCollection {
 | 
					 | 
				
			||||||
	if contextGroupCollectionInstance == nil {
 | 
					 | 
				
			||||||
		contextGroupCollectionInstance = &ContextGroupCollection{}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return contextGroupCollectionInstance
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func SetContextGroupCollection(collection ContextGroupCollection) *ContextGroupCollection {
 | 
					 | 
				
			||||||
	contextGroupCollectionInstance = &collection
 | 
					 | 
				
			||||||
	return contextGroupCollectionInstance
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (collection *ContextGroupCollection) FindContextGroupByNodeId(id string) *ContextGroup {
 | 
					 | 
				
			||||||
	var foundContextGroup *ContextGroup
 | 
					 | 
				
			||||||
	for i, g := range collection.Groups {
 | 
					 | 
				
			||||||
		if g.LinkedAreaList.Find(id) != nil {
 | 
					 | 
				
			||||||
			foundContextGroup = &collection.Groups[i]
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return found
 | 
				
			||||||
	return foundContextGroup
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (collection *ContextGroupCollection) CreateContextGroupFromProcessedArea(area ProcessedArea) bool {
 | 
					func (l *LinkedAreaList) InsertBefore(id string, processedArea ProcessedArea) bool {
 | 
				
			||||||
	fmt.Println("CreateContextGroupFromProcessedArea")
 | 
						found := false
 | 
				
			||||||
 | 
						for n := l.First(); n != nil && !found; n = n.GetNext() {
 | 
				
			||||||
	newLinkedAreaList := LinkedAreaList{}
 | 
							if n.Area.Id == id {
 | 
				
			||||||
	newLinkedAreaList.Push(area)
 | 
								found = true
 | 
				
			||||||
 | 
								newNode := &LinkedProcessedArea{Area: processedArea}
 | 
				
			||||||
	newContextGroup := ContextGroup{
 | 
								newNode.Next = n
 | 
				
			||||||
		Id:             uuid.NewString(),
 | 
								newNode.Previous = n.Previous
 | 
				
			||||||
		DocumentId:     area.DocumentId,
 | 
								n.Previous = newNode
 | 
				
			||||||
		LinkedAreaList: newLinkedAreaList,
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	collection.Groups = append(collection.Groups, newContextGroup)
 | 
						return found
 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: completely rework this linked list and the collection
 | 
					func (l *LinkedAreaList) Serialize() []SerializedLinkedProcessedArea {
 | 
				
			||||||
func (collection *ContextGroupCollection) ConnectAreaAsTailToNode(tailArea ProcessedArea, headArea ProcessedArea) bool {
 | 
						var serialized []SerializedLinkedProcessedArea
 | 
				
			||||||
	headNodeContextGroup := collection.FindContextGroupByNodeId(headArea.Id)
 | 
						for n := l.First(); n != nil; n = n.GetNext() {
 | 
				
			||||||
 | 
							areaId := n.Area.Id
 | 
				
			||||||
	if headNodeContextGroup == nil {
 | 
							previousId := ""
 | 
				
			||||||
		collection.CreateContextGroupFromProcessedArea(headArea)
 | 
							if n.Previous != nil {
 | 
				
			||||||
		headNodeContextGroup = collection.FindContextGroupByNodeId(headArea.Id)
 | 
								previousId = n.Previous.Area.Id
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nextId := ""
 | 
				
			||||||
 | 
							if n.Next != nil {
 | 
				
			||||||
 | 
								nextId = n.Next.Area.Id
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	headNode := headNodeContextGroup.LinkedAreaList.Find(headArea.Id)
 | 
							serialized = append(serialized, SerializedLinkedProcessedArea{
 | 
				
			||||||
	headNode.next = &LinkedProcessedArea{
 | 
								AreaId:     areaId,
 | 
				
			||||||
		Area:     tailArea,
 | 
								PreviousId: previousId,
 | 
				
			||||||
		previous: headNode,
 | 
								NextId:     nextId,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return serialized
 | 
				
			||||||
	return true
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DeserializeLinkedAreaList(serialized []SerializedLinkedProcessedArea) LinkedAreaList {
 | 
				
			||||||
 | 
						linkedAreaList := LinkedAreaList{}
 | 
				
			||||||
 | 
						for _, serializedLinkedProcessedArea := range serialized {
 | 
				
			||||||
 | 
							linkedAreaList.Push(ProcessedArea{
 | 
				
			||||||
 | 
								Id: serializedLinkedProcessedArea.AreaId,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, serializedLinkedProcessedArea := range serialized {
 | 
				
			||||||
 | 
							linkedProcessedArea := linkedAreaList.Find(serializedLinkedProcessedArea.AreaId)
 | 
				
			||||||
 | 
							if serializedLinkedProcessedArea.PreviousId != "" {
 | 
				
			||||||
 | 
								linkedProcessedArea.Previous = linkedAreaList.Find(serializedLinkedProcessedArea.PreviousId)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if serializedLinkedProcessedArea.NextId != "" {
 | 
				
			||||||
 | 
								linkedProcessedArea.Next = linkedAreaList.Find(serializedLinkedProcessedArea.NextId)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return linkedAreaList
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -12,39 +12,22 @@ import { useStage } from './context/provider'
 | 
				
			|||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
  isActive: boolean,
 | 
					  isActive: boolean,
 | 
				
			||||||
  area: entities.Area,
 | 
					  area: entities.Area,
 | 
				
			||||||
  setHoveredOverAreaIds: Function
 | 
					 | 
				
			||||||
  setHoveredProcessedArea: Function
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type coordinates = { x: number, y: number }
 | 
					type coordinates = { x: number, y: number }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Area = (props: Props) => {
 | 
					const Area = (props: Props) => {
 | 
				
			||||||
  const { getProcessedAreaById, selectedAreaId, setSelectedAreaId } = useProject()
 | 
					  const { selectedAreaId, setSelectedAreaId } = useProject()
 | 
				
			||||||
  const { scale } = useStage()
 | 
					  const { scale } = useStage()
 | 
				
			||||||
  const shapeRef = React.useRef<Konva.Rect>(null)
 | 
					  const shapeRef = React.useRef<Konva.Rect>(null)
 | 
				
			||||||
  const [isAreaContextMenuOpen, setIsAreaContextMenuOpen] = useState(false)
 | 
					  const [isAreaContextMenuOpen, setIsAreaContextMenuOpen] = useState(false)
 | 
				
			||||||
  const [areaContextMenuPosition, setAreaContextMenuPosition] = useState<coordinates>()
 | 
					  const [areaContextMenuPosition, setAreaContextMenuPosition] = useState<coordinates>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { area, isActive, setHoveredOverAreaIds, setHoveredProcessedArea } = props
 | 
					  const { area, isActive } = props
 | 
				
			||||||
  const a = area
 | 
					  const a = area
 | 
				
			||||||
  const width = (a.endX - a.startX)
 | 
					  const width = (a.endX - a.startX)
 | 
				
			||||||
  const height = (a.endY - a.startY)
 | 
					  const height = (a.endY - a.startY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleEnterOrLeave = (e: KonvaEventObject<MouseEvent>) => {
 | 
					 | 
				
			||||||
    const stage = e.currentTarget.getStage()!
 | 
					 | 
				
			||||||
    const currentMousePosition = stage.pointerPos
 | 
					 | 
				
			||||||
    const intersectingNodes = stage.getAllIntersections(currentMousePosition)
 | 
					 | 
				
			||||||
    const drawnAreas = intersectingNodes.filter(n => n.attrs?.isArea)
 | 
					 | 
				
			||||||
    const drawnAreasIds = drawnAreas.map(d => d.attrs?.id)
 | 
					 | 
				
			||||||
    setHoveredOverAreaIds(drawnAreasIds)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const processedAreaRequests = drawnAreasIds.map(a => getProcessedAreaById(a || ''))
 | 
					 | 
				
			||||||
    Promise.all(processedAreaRequests).then(responses => {
 | 
					 | 
				
			||||||
      const validResponses = responses.filter(r => r?.id) as entities.ProcessedArea[]
 | 
					 | 
				
			||||||
      setHoveredProcessedArea(validResponses || [])
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const handleContextMenu = (e: KonvaEventObject<PointerEvent>) => {
 | 
					  const handleContextMenu = (e: KonvaEventObject<PointerEvent>) => {
 | 
				
			||||||
    e.evt.preventDefault()
 | 
					    e.evt.preventDefault()
 | 
				
			||||||
    const stage = e.currentTarget.getStage()
 | 
					    const stage = e.currentTarget.getStage()
 | 
				
			||||||
@ -76,8 +59,6 @@ const Area = (props: Props) => {
 | 
				
			|||||||
      strokeWidth={1}
 | 
					      strokeWidth={1}
 | 
				
			||||||
      strokeScaleEnabled={false}
 | 
					      strokeScaleEnabled={false}
 | 
				
			||||||
      shadowForStrokeEnabled={false}
 | 
					      shadowForStrokeEnabled={false}
 | 
				
			||||||
      onMouseEnter={handleEnterOrLeave}
 | 
					 | 
				
			||||||
      onMouseLeave={handleEnterOrLeave}
 | 
					 | 
				
			||||||
      onClick={() => handleAreaClick(a.id)}
 | 
					      onClick={() => handleAreaClick(a.id)}
 | 
				
			||||||
      onContextMenu={handleContextMenu}
 | 
					      onContextMenu={handleContextMenu}
 | 
				
			||||||
      isArea
 | 
					      isArea
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
'use client'
 | 
					'use client'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React, { useState } from 'react'
 | 
					import React, { useEffect, useState } from 'react'
 | 
				
			||||||
import { Group } from 'react-konva'
 | 
					import { Group } from 'react-konva'
 | 
				
			||||||
import { useProject } from '../../context/Project/provider'
 | 
					import { useProject } from '../../context/Project/provider'
 | 
				
			||||||
import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
					import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
				
			||||||
@ -12,12 +12,24 @@ import { useStage } from './context/provider'
 | 
				
			|||||||
type Props = { scale: number }
 | 
					type Props = { scale: number }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Areas = ({ scale }: Props) => {
 | 
					const Areas = ({ scale }: Props) => {
 | 
				
			||||||
  const { getSelectedDocument, selectedAreaId } = useProject()
 | 
					  const { getSelectedDocument, selectedAreaId, getProcessedAreaById } = useProject()
 | 
				
			||||||
  const { isProcessedWordsVisible } = useStage()
 | 
					  const { isProcessedWordsVisible } = useStage()
 | 
				
			||||||
  const areas = getSelectedDocument()?.areas || []
 | 
					  const areas = getSelectedDocument()?.areas || []
 | 
				
			||||||
  const [hoveredOverAreaIds, setHoveredOverAreaIds] = useState<string[]>([])
 | 
					 | 
				
			||||||
  const [hoveredProcessedAreas, setHoveredProcessedArea] = useState<entities.ProcessedArea[]>([])
 | 
					 | 
				
			||||||
  const [editingWord, setEditingWord] = useState<entities.ProcessedWord | null>(null)
 | 
					  const [editingWord, setEditingWord] = useState<entities.ProcessedWord | null>(null)
 | 
				
			||||||
 | 
					  const [selectedProcessedArea, setSelectedProcessedArea] = useState<entities.ProcessedArea | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!selectedAreaId) return setSelectedProcessedArea(null)
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      getProcessedAreaById(selectedAreaId).then(res => {
 | 
				
			||||||
 | 
					        if (res) setSelectedProcessedArea(res)
 | 
				
			||||||
 | 
					      }).catch(err => {
 | 
				
			||||||
 | 
					        console.warn('getProcessedAreaById', err)
 | 
				
			||||||
 | 
					        setSelectedProcessedArea(null)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }, [selectedAreaId])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderEditingWord = () => {
 | 
					  const renderEditingWord = () => {
 | 
				
			||||||
    if (!editingWord) return
 | 
					    if (!editingWord) return
 | 
				
			||||||
@ -29,26 +41,20 @@ const Areas = ({ scale }: Props) => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderProcessedWords = () => {
 | 
					  const renderProcessedWords = () => {
 | 
				
			||||||
    if (!hoveredProcessedAreas.length) return
 | 
					    if (!selectedProcessedArea) return <></>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return hoveredProcessedAreas.map(a => {
 | 
					      const words = selectedProcessedArea.lines.map(l => l.words).flat()
 | 
				
			||||||
      const words = a.lines.map(l => l.words).flat()
 | 
					 | 
				
			||||||
      return words.map((w, index) => <ProcessedWord
 | 
					      return words.map((w, index) => <ProcessedWord
 | 
				
			||||||
        key={index}
 | 
					        key={index}
 | 
				
			||||||
        area={a}
 | 
					        area={selectedProcessedArea}
 | 
				
			||||||
        word={w}
 | 
					        word={w}
 | 
				
			||||||
        scale={scale}
 | 
					        scale={scale}
 | 
				
			||||||
        setEditingWord={setEditingWord}
 | 
					        setEditingWord={setEditingWord}
 | 
				
			||||||
      />)
 | 
					      />)
 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderAreas = (areas: entities.Area[]) => areas.map((a, index) => {
 | 
					  const renderAreas = (areas: entities.Area[]) => areas.map((a, index) => {
 | 
				
			||||||
    return <Area key={index}
 | 
					    return <Area key={index} area={a} isActive={a.id === selectedAreaId} />
 | 
				
			||||||
      area={a}
 | 
					 | 
				
			||||||
      setHoveredOverAreaIds={setHoveredOverAreaIds}
 | 
					 | 
				
			||||||
      setHoveredProcessedArea={setHoveredProcessedArea}
 | 
					 | 
				
			||||||
      isActive={(hoveredOverAreaIds.includes(a.id) || a.id === selectedAreaId)} />
 | 
					 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return <Group>
 | 
					  return <Group>
 | 
				
			||||||
 | 
				
			|||||||
@ -9,15 +9,15 @@ import useImage from 'use-image'
 | 
				
			|||||||
import { RectangleCoordinates } from './types'
 | 
					import { RectangleCoordinates } from './types'
 | 
				
			||||||
import DrawingArea from './DrawingArea'
 | 
					import DrawingArea from './DrawingArea'
 | 
				
			||||||
import getNormalizedRectToBounds from '../../utils/getNormalizedRectToBounds'
 | 
					import getNormalizedRectToBounds from '../../utils/getNormalizedRectToBounds'
 | 
				
			||||||
import processImageArea from '../../useCases/processImageArea'
 | 
					 | 
				
			||||||
import { useStage } from './context/provider'
 | 
					import { useStage } from './context/provider'
 | 
				
			||||||
import ContextConnections from './ContextConnections'
 | 
					import ContextConnections from './ContextConnections'
 | 
				
			||||||
 | 
					import processImageRect from '../../useCases/processImageRect'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let downClickX: number
 | 
					let downClickX: number
 | 
				
			||||||
let downClickY: number
 | 
					let downClickY: number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CanvasStage = () => {
 | 
					const CanvasStage = () => {
 | 
				
			||||||
  const { getSelectedDocument, requestAddArea, setSelectedAreaId } = useProject()
 | 
					  const { getSelectedDocument, updateDocuments, setSelectedAreaId } = useProject()
 | 
				
			||||||
  const { scale, scaleStep, maxScale, size, setScale, isAreasVisible, isLinkAreaContextsVisible, isDrawingArea, setIsDrawingArea, startingContextConnection, setStartingContextConnection } = useStage()
 | 
					  const { scale, scaleStep, maxScale, size, setScale, isAreasVisible, isLinkAreaContextsVisible, isDrawingArea, setIsDrawingArea, startingContextConnection, setStartingContextConnection } = useStage()
 | 
				
			||||||
  const [documentImage] = useImage(getSelectedDocument()?.path || '')
 | 
					  const [documentImage] = useImage(getSelectedDocument()?.path || '')
 | 
				
			||||||
  const documentRef = useRef(null)
 | 
					  const documentRef = useRef(null)
 | 
				
			||||||
@ -55,11 +55,12 @@ const CanvasStage = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const normalizedDrawnRect = getNormalizedRectToBounds(drawingAreaRect, documentWidth, documentHeight, scale)
 | 
					    const normalizedDrawnRect = getNormalizedRectToBounds(drawingAreaRect, documentWidth, documentHeight, scale)
 | 
				
			||||||
    const selectedDocumentId = getSelectedDocument()!.id
 | 
					    const selectedDocumentId = getSelectedDocument()!.id
 | 
				
			||||||
    requestAddArea(selectedDocumentId, normalizedDrawnRect).then(addedArea => {
 | 
					    processImageRect(selectedDocumentId, normalizedDrawnRect).then(async addedAreas => {
 | 
				
			||||||
      setSelectedAreaId(addedArea.id)
 | 
					      updateDocuments().then(response => {
 | 
				
			||||||
      processImageArea(selectedDocumentId, addedArea.id)
 | 
					        if (!addedAreas.length) return
 | 
				
			||||||
 | 
					        setSelectedAreaId(addedAreas[0].id)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					 | 
				
			||||||
    setDrawingAreaRect(null)
 | 
					    setDrawingAreaRect(null)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					'use client'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import React from 'react'
 | 
				
			||||||
 | 
					import { Group, Line } from 'react-konva'
 | 
				
			||||||
 | 
					import { useProject } from '../../../context/Project/provider'
 | 
				
			||||||
 | 
					import { useStage } from '../context/provider'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ConnectionLines = () => {
 | 
				
			||||||
 | 
					  const { scale } = useStage()
 | 
				
			||||||
 | 
					  const { getSelectedDocument, contextGroups } = useProject()
 | 
				
			||||||
 | 
					  const areas = getSelectedDocument()?.areas || []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const renderLines = () => {
 | 
				
			||||||
 | 
					    console.log('contextGroups', contextGroups)
 | 
				
			||||||
 | 
					    if (!contextGroups?.length) return <></>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const linesAlreadyRendered = new Set<string>()
 | 
				
			||||||
 | 
					    const lines = contextGroups.map((contextGroup) => {
 | 
				
			||||||
 | 
					      const currentArea = areas.find(a => a.id === contextGroup.areaId)
 | 
				
			||||||
 | 
					      const nextArea = areas.find(a => a.id === contextGroup.nextId)
 | 
				
			||||||
 | 
					      if (!currentArea || !nextArea) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (linesAlreadyRendered.has(`${contextGroup.areaId}-${contextGroup.nextId}`)) return
 | 
				
			||||||
 | 
					      if (linesAlreadyRendered.has(`${contextGroup.nextId}-${contextGroup.areaId}`)) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const startingPoint = {
 | 
				
			||||||
 | 
					        x: ((currentArea.startX + currentArea.endX) * scale) / 2,
 | 
				
			||||||
 | 
					        y: currentArea.startY * scale
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const startingTensionPoint = {
 | 
				
			||||||
 | 
					        x: (startingPoint.x + (nextArea.startX * scale)) / 2,
 | 
				
			||||||
 | 
					        y: startingPoint.y,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const endingPoint = {
 | 
				
			||||||
 | 
					        x: ((nextArea.startX + nextArea.endX) * scale) / 2,
 | 
				
			||||||
 | 
					        y: nextArea.endY * scale
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const endingTensionPoint = {
 | 
				
			||||||
 | 
					        x: (startingPoint.x + (nextArea.startX * scale)) / 2,
 | 
				
			||||||
 | 
					        y: endingPoint.y,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      linesAlreadyRendered.add(`${contextGroup.areaId}-${contextGroup.nextId}`)
 | 
				
			||||||
 | 
					      linesAlreadyRendered.add(`${contextGroup.nextId}-${contextGroup.areaId}`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return <Line
 | 
				
			||||||
 | 
					        key={`${contextGroup.areaId}-${contextGroup.nextId}`}
 | 
				
			||||||
 | 
					        points={[
 | 
				
			||||||
 | 
					          ...Object.values(startingPoint),
 | 
				
			||||||
 | 
					          ...Object.values(startingTensionPoint),
 | 
				
			||||||
 | 
					          ...Object.values(endingTensionPoint),
 | 
				
			||||||
 | 
					          ...Object.values(endingPoint),
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        strokeEnabled
 | 
				
			||||||
 | 
					        strokeWidth={2 * scale}
 | 
				
			||||||
 | 
					        stroke='#dc8dec'
 | 
				
			||||||
 | 
					        strokeScaleEnabled={false}
 | 
				
			||||||
 | 
					        shadowForStrokeEnabled={false}
 | 
				
			||||||
 | 
					        tension={0.2}
 | 
				
			||||||
 | 
					        listening={false}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    return lines.filter(l => !!l)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <Group>{renderLines()}</Group>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ConnectionLines
 | 
				
			||||||
@ -4,14 +4,14 @@ import { Circle, Group } from 'react-konva'
 | 
				
			|||||||
import { useStage } from '../context/provider'
 | 
					import { useStage } from '../context/provider'
 | 
				
			||||||
import { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
					import { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
				
			||||||
import { KonvaEventObject } from 'konva/lib/Node'
 | 
					import { KonvaEventObject } from 'konva/lib/Node'
 | 
				
			||||||
import { RequestConnectAreaAsTailToNode } from '../../../wailsjs/wailsjs/go/ipc/Channel'
 | 
					import { useProject } from '../../../context/Project/provider'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = { areas: entities.Area[] }
 | 
					type Props = { areas: entities.Area[] }
 | 
				
			||||||
const ConnectionPoints = (props: Props) => {
 | 
					const ConnectionPoints = (props: Props) => {
 | 
				
			||||||
  const { isLinkAreaContextsVisible, scale, startingContextConnection, setStartingContextConnection } = useStage()
 | 
					  const { isLinkAreaContextsVisible, scale, startingContextConnection, setStartingContextConnection } = useStage()
 | 
				
			||||||
 | 
					  const { requestConnectProcessedAreas } = useProject()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleContextAreaMouseDown = async (e: KonvaEventObject<MouseEvent>) => {
 | 
				
			||||||
  const handleContextAreaMouseDown = (e: KonvaEventObject<MouseEvent>) => {
 | 
					 | 
				
			||||||
    e.cancelBubble = true
 | 
					    e.cancelBubble = true
 | 
				
			||||||
    const clickedConnectionPoint = {
 | 
					    const clickedConnectionPoint = {
 | 
				
			||||||
      isHead: e.currentTarget.attrs.isHead,
 | 
					      isHead: e.currentTarget.attrs.isHead,
 | 
				
			||||||
@ -24,10 +24,15 @@ const ConnectionPoints = (props: Props) => {
 | 
				
			|||||||
      || clickedConnectionPoint.areaId === startingContextConnection.areaId)
 | 
					      || clickedConnectionPoint.areaId === startingContextConnection.areaId)
 | 
				
			||||||
      return setStartingContextConnection(null)
 | 
					      return setStartingContextConnection(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    console.log('connected points', startingContextConnection, clickedConnectionPoint)
 | 
					    const headId = startingContextConnection.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
				
			||||||
    const headId = clickedConnectionPoint.isHead ? clickedConnectionPoint.areaId : startingContextConnection.areaId
 | 
					    const tailId = !startingContextConnection.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
				
			||||||
    const tailId = !clickedConnectionPoint.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
					    setStartingContextConnection(null)
 | 
				
			||||||
    RequestConnectAreaAsTailToNode(headId, tailId).then(res => console.log(res)).catch(err => console.warn(err))
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      await requestConnectProcessedAreas(headId, tailId)
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      console.warn('RequestConnectProcessedAreas', err)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const renderConnectingPointsForArea = (a: entities.Area) => {
 | 
					  const renderConnectingPointsForArea = (a: entities.Area) => {
 | 
				
			||||||
@ -36,7 +41,7 @@ const ConnectionPoints = (props: Props) => {
 | 
				
			|||||||
    const headConnector = <Circle
 | 
					    const headConnector = <Circle
 | 
				
			||||||
      key={`head-${a.id}`}
 | 
					      key={`head-${a.id}`}
 | 
				
			||||||
      id={a.id}
 | 
					      id={a.id}
 | 
				
			||||||
      radius={10}
 | 
					      radius={8}
 | 
				
			||||||
      x={((a.startX + a.endX) * scale) / 2}
 | 
					      x={((a.startX + a.endX) * scale) / 2}
 | 
				
			||||||
      y={a.startY * scale}
 | 
					      y={a.startY * scale}
 | 
				
			||||||
      strokeEnabled={false}
 | 
					      strokeEnabled={false}
 | 
				
			||||||
@ -84,7 +89,7 @@ const ConnectionPoints = (props: Props) => {
 | 
				
			|||||||
      />)
 | 
					      />)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return <Group>
 | 
					    return <Group key={`group-${a.id}`}>
 | 
				
			||||||
      {connectorsToRender}
 | 
					      {connectorsToRender}
 | 
				
			||||||
    </Group>
 | 
					    </Group>
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -2,18 +2,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import React from 'react'
 | 
					import React from 'react'
 | 
				
			||||||
import { Line } from 'react-konva'
 | 
					import { Line } from 'react-konva'
 | 
				
			||||||
import { StartingContextConnection } from '../context/types'
 | 
					 | 
				
			||||||
import { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
					 | 
				
			||||||
import { Coordinates } from '../types'
 | 
					import { Coordinates } from '../types'
 | 
				
			||||||
 | 
					import { useStage } from '../context/provider'
 | 
				
			||||||
 | 
					import { useProject } from '../../../context/Project/provider'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CurrentDrawingConnectionProps = {
 | 
					type CurrentDrawingConnectionProps = {
 | 
				
			||||||
  startingContextConnection: StartingContextConnection | null
 | 
					 | 
				
			||||||
  areas: entities.Area[],
 | 
					 | 
				
			||||||
  scale: number,
 | 
					 | 
				
			||||||
  endDrawingPosition: Coordinates | null
 | 
					  endDrawingPosition: Coordinates | null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
const CurrentDrawingConnection = (props: CurrentDrawingConnectionProps) => {
 | 
					const CurrentDrawingConnection = (props: CurrentDrawingConnectionProps) => {
 | 
				
			||||||
  const { startingContextConnection, areas, scale, endDrawingPosition } = props 
 | 
					  const { endDrawingPosition } = props 
 | 
				
			||||||
 | 
					  const { startingContextConnection, scale } = useStage()
 | 
				
			||||||
 | 
					  const { getSelectedDocument } = useProject()
 | 
				
			||||||
 | 
					  const areas = getSelectedDocument()?.areas || []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!startingContextConnection || !endDrawingPosition) return <></>
 | 
					  if (!startingContextConnection || !endDrawingPosition) return <></>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { areaId, isHead } = startingContextConnection
 | 
					  const { areaId, isHead } = startingContextConnection
 | 
				
			||||||
@ -49,6 +50,7 @@ const CurrentDrawingConnection = (props: CurrentDrawingConnectionProps) => {
 | 
				
			|||||||
    strokeScaleEnabled={false}
 | 
					    strokeScaleEnabled={false}
 | 
				
			||||||
    shadowForStrokeEnabled={false}
 | 
					    shadowForStrokeEnabled={false}
 | 
				
			||||||
    tension={0.2}
 | 
					    tension={0.2}
 | 
				
			||||||
 | 
					    listening={false}
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,10 +8,11 @@ import Konva from 'konva'
 | 
				
			|||||||
import { Coordinates } from '../types'
 | 
					import { Coordinates } from '../types'
 | 
				
			||||||
import CurrentDrawingConnection from './CurrentDrawingConnection'
 | 
					import CurrentDrawingConnection from './CurrentDrawingConnection'
 | 
				
			||||||
import ConnectionPoints from './ConnectionPoints'
 | 
					import ConnectionPoints from './ConnectionPoints'
 | 
				
			||||||
 | 
					import ConnectionLines from './ConnectionLines'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ContextConnections = () => {
 | 
					const ContextConnections = () => {
 | 
				
			||||||
  const { getSelectedDocument } = useProject()
 | 
					  const { getSelectedDocument } = useProject()
 | 
				
			||||||
  const { isLinkAreaContextsVisible, startingContextConnection, setStartingContextConnection, scale } = useStage()
 | 
					  const { isLinkAreaContextsVisible, startingContextConnection, scale } = useStage()
 | 
				
			||||||
  const areas = getSelectedDocument()?.areas || []
 | 
					  const areas = getSelectedDocument()?.areas || []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [endDrawingPosition, setEndDrawingPosition] = useState<Coordinates | null>(null)
 | 
					  const [endDrawingPosition, setEndDrawingPosition] = useState<Coordinates | null>(null)
 | 
				
			||||||
@ -34,7 +35,8 @@ const ContextConnections = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return <Group>
 | 
					  return <Group>
 | 
				
			||||||
    <ConnectionPoints areas={areas} />
 | 
					    <ConnectionPoints areas={areas} />
 | 
				
			||||||
    <CurrentDrawingConnection areas={areas} startingContextConnection={startingContextConnection} endDrawingPosition={endDrawingPosition} scale={scale} />
 | 
					    <ConnectionLines />
 | 
				
			||||||
 | 
					    <CurrentDrawingConnection endDrawingPosition={endDrawingPosition} />
 | 
				
			||||||
  </Group>
 | 
					  </Group>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ type Icon = (props: React.SVGProps<SVGSVGElement> & {
 | 
				
			|||||||
}) => JSX.Element
 | 
					}) => JSX.Element
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ToolToggleButton = (props: { icon: Icon, hint: string, isActive: boolean, onClick?: React.MouseEventHandler<HTMLButtonElement> }) => {
 | 
					const ToolToggleButton = (props: { icon: Icon, hint: string, isActive: boolean, onClick?: React.MouseEventHandler<HTMLButtonElement> }) => {
 | 
				
			||||||
  return <div className="group flex relative pointer-events-auto">
 | 
					  return <div className="group flex relative">
 | 
				
			||||||
    <button className='pointer-events-auto p-2 bg-white rounded-md block mt-3 shadow-lg hover:bg-slate-100 aria-pressed:bg-indigo-400 aria-pressed:text-white'
 | 
					    <button className='pointer-events-auto p-2 bg-white rounded-md block mt-3 shadow-lg hover:bg-slate-100 aria-pressed:bg-indigo-400 aria-pressed:text-white'
 | 
				
			||||||
      aria-pressed={props.isActive}
 | 
					      aria-pressed={props.isActive}
 | 
				
			||||||
      onClick={props.onClick}>
 | 
					      onClick={props.onClick}>
 | 
				
			||||||
 | 
				
			|||||||
@ -7,10 +7,13 @@ import { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
				
			|||||||
import LanguageSelect from '../../utils/LanguageSelect'
 | 
					import LanguageSelect from '../../utils/LanguageSelect'
 | 
				
			||||||
import { useStage } from '../context/provider'
 | 
					import { useStage } from '../context/provider'
 | 
				
			||||||
import ToolToggleButton from './ToolToggleButton'
 | 
					import ToolToggleButton from './ToolToggleButton'
 | 
				
			||||||
 | 
					import { useNotification } from '../../../context/Notification/provider'
 | 
				
			||||||
 | 
					import processImageArea from '../../../useCases/processImageArea'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ToolingOverlay = () => {
 | 
					const ToolingOverlay = () => {
 | 
				
			||||||
  const { getSelectedDocument, selectedAreaId, } = useProject()
 | 
					  const { getSelectedDocument, selectedAreaId, requestUpdateArea, requestUpdateDocument, updateDocuments } = useProject()
 | 
				
			||||||
 | 
					  const { addNotificationToQueue } = useNotification()
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    scale, scaleStep, maxScale, setScale,
 | 
					    scale, scaleStep, maxScale, setScale,
 | 
				
			||||||
    isLinkAreaContextsVisible, setIsLinkAreaContextsVisible,
 | 
					    isLinkAreaContextsVisible, setIsLinkAreaContextsVisible,
 | 
				
			||||||
@ -24,7 +27,54 @@ const ToolingOverlay = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    setSelectedArea(selectedDocument?.areas.find(a => a.id == selectedAreaId))
 | 
					    setSelectedArea(selectedDocument?.areas.find(a => a.id == selectedAreaId))
 | 
				
			||||||
  }, [selectedAreaId])
 | 
					  }, [selectedAreaId, selectedDocument, selectedArea])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleAreaProcessLanguageSelect = async (selectedLanguage: entities.Language) => {
 | 
				
			||||||
 | 
					    if (!selectedArea) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let successfullyUpdatedLanguageOnArea = false
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      successfullyUpdatedLanguageOnArea = await requestUpdateArea({ ...selectedArea, ...{ language: selectedLanguage } })
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      addNotificationToQueue({ message: 'Error updating area language', level: 'error' })
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const selectedDocumentId = getSelectedDocument()?.id
 | 
				
			||||||
 | 
					    if (!successfullyUpdatedLanguageOnArea || !selectedDocumentId) {
 | 
				
			||||||
 | 
					      addNotificationToQueue({ message: 'Did not successfully update area language', level: 'warning' })
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      await processImageArea(selectedDocumentId, selectedArea.id)
 | 
				
			||||||
 | 
					      await updateDocuments()
 | 
				
			||||||
 | 
					      addNotificationToQueue({ message: 'Finished processing area', level: 'info' })
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      addNotificationToQueue({ message: 'Error processing area', level: 'error' })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleDocumentProcessLanguageSelect = async (selectedLanguage: entities.Language) => {
 | 
				
			||||||
 | 
					    if (!selectedDocument) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const currentDocument = selectedDocument
 | 
				
			||||||
 | 
					    currentDocument.defaultLanguage = selectedLanguage
 | 
				
			||||||
 | 
					    await requestUpdateDocument(currentDocument)
 | 
				
			||||||
 | 
					    await updateDocuments()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const renderLanguageSelect = () => {
 | 
				
			||||||
 | 
					    const defaultLanguage = selectedArea?.language.displayName ? selectedArea?.language : selectedDocument?.defaultLanguage
 | 
				
			||||||
 | 
					    const onSelect = selectedArea ? handleAreaProcessLanguageSelect : handleDocumentProcessLanguageSelect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return <LanguageSelect
 | 
				
			||||||
 | 
					      styles={{ fontSize: '16px', borderRadius: '2px' }}
 | 
				
			||||||
 | 
					      defaultLanguage={defaultLanguage}
 | 
				
			||||||
 | 
					      onSelect={onSelect}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return <>
 | 
					  return <>
 | 
				
			||||||
    {/* Top buttons */}
 | 
					    {/* Top buttons */}
 | 
				
			||||||
@ -36,7 +86,8 @@ const ToolingOverlay = () => {
 | 
				
			|||||||
            : selectedDocument?.name
 | 
					            : selectedDocument?.name
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        </h1>
 | 
					        </h1>
 | 
				
			||||||
        <LanguageSelect styles={{ fontSize: '16px', borderRadius: '2px' }} defaultLanguage={selectedArea?.language || selectedDocument?.defaultLanguage} />
 | 
					        { renderLanguageSelect() }
 | 
				
			||||||
 | 
					        {/* <LanguageSelect styles={{ fontSize: '16px', borderRadius: '2px' }} defaultLanguage={selectedArea?.language.displayName ? selectedArea?.language : selectedDocument?.defaultLanguage} /> */}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div className='flex mt-4 justify-evenly align-top pointer-events-auto'>
 | 
					      <div className='flex mt-4 justify-evenly align-top pointer-events-auto'>
 | 
				
			||||||
        <MagnifyingGlassMinusIcon className='w-4 h-4' />
 | 
					        <MagnifyingGlassMinusIcon className='w-4 h-4' />
 | 
				
			||||||
 | 
				
			|||||||
@ -15,13 +15,13 @@ const AreaLineItem = (props: { area: SidebarArea, documentId: string, index: num
 | 
				
			|||||||
    getAreaById,
 | 
					    getAreaById,
 | 
				
			||||||
    requestUpdateArea,
 | 
					    requestUpdateArea,
 | 
				
			||||||
    setSelectedDocumentId,
 | 
					    setSelectedDocumentId,
 | 
				
			||||||
    setSelectedAreaId,
 | 
					 | 
				
			||||||
    requestChangeAreaOrder,
 | 
					    requestChangeAreaOrder,
 | 
				
			||||||
    requestDeleteAreaById,
 | 
					    requestDeleteAreaById,
 | 
				
			||||||
 | 
					    selectedAreaId,
 | 
				
			||||||
 | 
					    setSelectedAreaId,
 | 
				
			||||||
  } = useProject()
 | 
					  } = useProject()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const {
 | 
					  const {
 | 
				
			||||||
    selectedAreaId,
 | 
					 | 
				
			||||||
    isEditAreaNameInputShowing,
 | 
					    isEditAreaNameInputShowing,
 | 
				
			||||||
    setIsEditAreaNameInputShowing,
 | 
					    setIsEditAreaNameInputShowing,
 | 
				
			||||||
    dragOverAreaId,
 | 
					    dragOverAreaId,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								frontend/consts/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								frontend/consts/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					const colors = {
 | 
				
			||||||
 | 
					  BRAND_PRIMARY: {
 | 
				
			||||||
 | 
					    hex: '#dc8dec',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { colors }
 | 
				
			||||||
@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import { saveContextGroups } from '../../useCases/saveData'
 | 
				
			||||||
 | 
					import { RequestConnectProcessedAreas, GetSerializedContextGroups } from '../../wailsjs/wailsjs/go/ipc/Channel'
 | 
				
			||||||
 | 
					import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Dependencies = { updateDocuments: Function }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createContextGroupProviderMethods = (dependencies?: Dependencies) => {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    const requestConnectProcessedAreas = async (headId: string, tailId: string) => {
 | 
				
			||||||
 | 
					      let wasSuccessful = false
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        wasSuccessful = await RequestConnectProcessedAreas(headId, tailId)
 | 
				
			||||||
 | 
					        await saveContextGroups()
 | 
				
			||||||
 | 
					      } catch (err) {
 | 
				
			||||||
 | 
					        console.error(err)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      dependencies?.updateDocuments()
 | 
				
			||||||
 | 
					      return wasSuccessful
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    const getSerializedContextGroups = async () => {
 | 
				
			||||||
 | 
					      let response: entities.SerializedLinkedProcessedArea[] = []
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        response = await GetSerializedContextGroups()
 | 
				
			||||||
 | 
					      } catch (err) {
 | 
				
			||||||
 | 
					        console.error(err)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      requestConnectProcessedAreas,
 | 
				
			||||||
 | 
					      getSerializedContextGroups,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default createContextGroupProviderMethods
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { saveUserProcessedMarkdown } from '../../useCases/saveData'
 | 
					import { saveUserProcessedMarkdown } from '../../useCases/saveData'
 | 
				
			||||||
import { GetUserMarkdownByDocumentId, RequestUpdateDocumentUserMarkdown } from '../../wailsjs/wailsjs/go/ipc/Channel'
 | 
					import { GetUserMarkdownByDocumentId, RequestUpdateDocumentUserMarkdown } from '../../wailsjs/wailsjs/go/ipc/Channel'
 | 
				
			||||||
import { ipc, entities } from '../../wailsjs/wailsjs/go/models'
 | 
					import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Dependencies = {}
 | 
					type Dependencies = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
					import { entities, ipc } from '../../wailsjs/wailsjs/go/models'
 | 
				
			||||||
import { ProjectContextType, UserProps } from './types'
 | 
					import { ProjectContextType, UserProps } from './types'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const makeDefaultProject = (): ProjectContextType => ({
 | 
					const makeDefaultProject = (): ProjectContextType => ({
 | 
				
			||||||
  id: '',
 | 
					  id: '',
 | 
				
			||||||
  documents: [] as entities.Document[],
 | 
					  documents: [] as entities.Document[],
 | 
				
			||||||
  groups: [] as entities.Group[],
 | 
					  groups: [] as entities.Group[],
 | 
				
			||||||
 | 
					  contextGroups: [] as entities.SerializedLinkedProcessedArea[],
 | 
				
			||||||
  selectedAreaId: '',
 | 
					  selectedAreaId: '',
 | 
				
			||||||
  selectedDocumentId: '',
 | 
					  selectedDocumentId: '',
 | 
				
			||||||
  getSelectedDocument: () => new entities.Document(),
 | 
					  getSelectedDocument: () => new entities.Document(),
 | 
				
			||||||
@ -33,6 +34,9 @@ const makeDefaultProject = (): ProjectContextType => ({
 | 
				
			|||||||
  requestUpdateProcessedWordById: (wordId, newTestValue) => Promise.resolve(false),
 | 
					  requestUpdateProcessedWordById: (wordId, newTestValue) => Promise.resolve(false),
 | 
				
			||||||
  getProcessedAreaById: (areaId) => Promise.resolve(undefined),
 | 
					  getProcessedAreaById: (areaId) => Promise.resolve(undefined),
 | 
				
			||||||
  requestUpdateProcessedArea: updatedProcessedArea => Promise.resolve(false),
 | 
					  requestUpdateProcessedArea: updatedProcessedArea => Promise.resolve(false),
 | 
				
			||||||
 | 
					  requestConnectProcessedAreas: (headId, tailId) => Promise.resolve(false),
 | 
				
			||||||
 | 
					  getSerializedContextGroups: () => Promise.resolve([]),
 | 
				
			||||||
 | 
					  updateDocuments: () => Promise.resolve(new ipc.GetDocumentsResponse())
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default makeDefaultProject
 | 
					export default makeDefaultProject
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ import createAreaProviderMethods from './createAreaProviderMethods'
 | 
				
			|||||||
import createDocumentProviderMethods from './createDocumentMethods'
 | 
					import createDocumentProviderMethods from './createDocumentMethods'
 | 
				
			||||||
import createSessionProviderMethods from './createSessionProviderMethods'
 | 
					import createSessionProviderMethods from './createSessionProviderMethods'
 | 
				
			||||||
import createUserMarkdownProviderMethods from './createUserMarkdownProviderMethods'
 | 
					import createUserMarkdownProviderMethods from './createUserMarkdownProviderMethods'
 | 
				
			||||||
 | 
					import createContextGroupProviderMethods from './createContextGroupProviderMethods'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
 | 
					const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,15 +22,17 @@ type Props = { children: ReactNode, projectProps: ProjectProps }
 | 
				
			|||||||
export function ProjectProvider({ children, projectProps }: Props) {
 | 
					export function ProjectProvider({ children, projectProps }: Props) {
 | 
				
			||||||
  const [documents, setDocuments] = useState<entities.Document[]>(projectProps.documents)
 | 
					  const [documents, setDocuments] = useState<entities.Document[]>(projectProps.documents)
 | 
				
			||||||
  const [groups, setGroups] = useState<entities.Group[]>(projectProps.groups)
 | 
					  const [groups, setGroups] = useState<entities.Group[]>(projectProps.groups)
 | 
				
			||||||
 | 
					  const [contextGroups, setContextGroups] = useState<entities.SerializedLinkedProcessedArea[]>(projectProps.contextGroups)
 | 
				
			||||||
  const [selectedAreaId, setSelectedAreaId] = useState<string>('')
 | 
					  const [selectedAreaId, setSelectedAreaId] = useState<string>('')
 | 
				
			||||||
  const [selectedDocumentId, setSelectedDocumentId] = useState<string>('')
 | 
					  const [selectedDocumentId, setSelectedDocumentId] = useState<string>('')
 | 
				
			||||||
  const [currentSession, setCurrentSession] = useState<entities.Session>(new entities.Session())
 | 
					  const [currentSession, setCurrentSession] = useState<entities.Session>(new entities.Session())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const updateDocuments = async () => {
 | 
					  const updateDocuments = async () => {
 | 
				
			||||||
    const response = await GetDocuments()
 | 
					    const response = await GetDocuments()
 | 
				
			||||||
    const { documents, groups } = response
 | 
					    const { documents, groups, contextGroups } = response
 | 
				
			||||||
    setDocuments(documents)
 | 
					    setDocuments(documents)
 | 
				
			||||||
    setGroups(groups)
 | 
					    setGroups(groups)
 | 
				
			||||||
 | 
					    setContextGroups(contextGroups)
 | 
				
			||||||
    return response
 | 
					    return response
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,6 +46,7 @@ export function ProjectProvider({ children, projectProps }: Props) {
 | 
				
			|||||||
  const areaMethods = createAreaProviderMethods({ documents, updateDocuments, selectedDocumentId })
 | 
					  const areaMethods = createAreaProviderMethods({ documents, updateDocuments, selectedDocumentId })
 | 
				
			||||||
  const sessionMethods = createSessionProviderMethods({ updateSession, updateDocuments })
 | 
					  const sessionMethods = createSessionProviderMethods({ updateSession, updateDocuments })
 | 
				
			||||||
  const userMarkDownMethods = createUserMarkdownProviderMethods()
 | 
					  const userMarkDownMethods = createUserMarkdownProviderMethods()
 | 
				
			||||||
 | 
					  const contextGroupMethods = createContextGroupProviderMethods({ updateDocuments })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
@ -60,15 +64,18 @@ export function ProjectProvider({ children, projectProps }: Props) {
 | 
				
			|||||||
    id: '',
 | 
					    id: '',
 | 
				
			||||||
    documents,
 | 
					    documents,
 | 
				
			||||||
    groups,
 | 
					    groups,
 | 
				
			||||||
 | 
					    contextGroups,
 | 
				
			||||||
    selectedAreaId,
 | 
					    selectedAreaId,
 | 
				
			||||||
    setSelectedAreaId,
 | 
					    setSelectedAreaId,
 | 
				
			||||||
    selectedDocumentId,
 | 
					    selectedDocumentId,
 | 
				
			||||||
    setSelectedDocumentId,
 | 
					    setSelectedDocumentId,
 | 
				
			||||||
    currentSession,
 | 
					    currentSession,
 | 
				
			||||||
 | 
					    updateDocuments,
 | 
				
			||||||
    ...areaMethods,
 | 
					    ...areaMethods,
 | 
				
			||||||
    ...documentMethods,
 | 
					    ...documentMethods,
 | 
				
			||||||
    ...sessionMethods,
 | 
					    ...sessionMethods,
 | 
				
			||||||
    ...userMarkDownMethods,
 | 
					    ...userMarkDownMethods,
 | 
				
			||||||
 | 
					    ...contextGroupMethods,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return <ProjectContext.Provider value={value}>
 | 
					  return <ProjectContext.Provider value={value}>
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ export type ProjectProps = {
 | 
				
			|||||||
  id: string,
 | 
					  id: string,
 | 
				
			||||||
  documents: entities.Document[],
 | 
					  documents: entities.Document[],
 | 
				
			||||||
  groups: entities.Group[],
 | 
					  groups: entities.Group[],
 | 
				
			||||||
 | 
					  contextGroups: entities.SerializedLinkedProcessedArea[],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type AddAreaProps = {
 | 
					export type AddAreaProps = {
 | 
				
			||||||
@ -40,7 +41,7 @@ export type ProjectContextType = {
 | 
				
			|||||||
  getSelectedDocument: () => entities.Document | undefined
 | 
					  getSelectedDocument: () => entities.Document | undefined
 | 
				
			||||||
  getAreaById: (areaId: string) => entities.Area | undefined
 | 
					  getAreaById: (areaId: string) => entities.Area | undefined
 | 
				
			||||||
  getProcessedAreasByDocumentId: (documentId: string) => Promise<entities.ProcessedArea[]>
 | 
					  getProcessedAreasByDocumentId: (documentId: string) => Promise<entities.ProcessedArea[]>
 | 
				
			||||||
  requestAddProcessedArea: (processedArea: entities.ProcessedArea) => Promise<boolean>
 | 
					  requestAddProcessedArea: (processedArea: entities.ProcessedArea) => Promise<entities.ProcessedArea>
 | 
				
			||||||
  requestAddArea: (documentId: string, area: AddAreaProps) => Promise<entities.Area>
 | 
					  requestAddArea: (documentId: string, area: AddAreaProps) => Promise<entities.Area>
 | 
				
			||||||
  requestUpdateArea: (area: AreaProps) => Promise<boolean>
 | 
					  requestUpdateArea: (area: AreaProps) => Promise<boolean>
 | 
				
			||||||
  requestDeleteAreaById: (areaId: string) => Promise<boolean>
 | 
					  requestDeleteAreaById: (areaId: string) => Promise<boolean>
 | 
				
			||||||
@ -65,4 +66,7 @@ export type ProjectContextType = {
 | 
				
			|||||||
  requestUpdateProcessedWordById: (wordId: string, newTextValue: string) => Promise<boolean>
 | 
					  requestUpdateProcessedWordById: (wordId: string, newTextValue: string) => Promise<boolean>
 | 
				
			||||||
  getProcessedAreaById: (areaId: string) => Promise<entities.ProcessedArea | undefined>
 | 
					  getProcessedAreaById: (areaId: string) => Promise<entities.ProcessedArea | undefined>
 | 
				
			||||||
  requestUpdateProcessedArea: (updatedProcessedArea: entities.ProcessedArea) => Promise<boolean>
 | 
					  requestUpdateProcessedArea: (updatedProcessedArea: entities.ProcessedArea) => Promise<boolean>
 | 
				
			||||||
 | 
					  requestConnectProcessedAreas: (headId: string, tailId: string) => Promise<boolean>
 | 
				
			||||||
 | 
					  getSerializedContextGroups: () => Promise<entities.SerializedLinkedProcessedArea[]>
 | 
				
			||||||
 | 
					  updateDocuments: () => Promise<ipc.GetDocumentsResponse>
 | 
				
			||||||
} & ProjectProps
 | 
					} & ProjectProps
 | 
				
			||||||
@ -16,4 +16,7 @@ module.exports = {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  colors: {
 | 
				
			||||||
 | 
					    brandPrimary: '#dc8dec',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { createScheduler, createWorker } from 'tesseract.js'
 | 
					import { createScheduler, createWorker, PSM } from 'tesseract.js'
 | 
				
			||||||
import { GetAreaById, GetDocumentById, GetProcessedAreaById, RequestAddProcessedArea, RequestSaveProcessedTextCollection, RequestUpdateProcessedArea } from '../wailsjs/wailsjs/go/ipc/Channel'
 | 
					import { GetAreaById, GetDocumentById, GetProcessedAreaById, RequestAddProcessedArea, RequestSaveProcessedTextCollection, RequestUpdateProcessedArea } from '../wailsjs/wailsjs/go/ipc/Channel'
 | 
				
			||||||
import { entities } from '../wailsjs/wailsjs/go/models'
 | 
					import { entities } from '../wailsjs/wailsjs/go/models'
 | 
				
			||||||
import loadImage from './loadImage'
 | 
					import loadImage from './loadImage'
 | 
				
			||||||
@ -79,11 +79,15 @@ const processImageArea = async (documentId: string, areaId: string) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const existingProcessedArea = await GetProcessedAreaById(areaId)
 | 
					  const existingProcessedArea = await GetProcessedAreaById(areaId)
 | 
				
			||||||
  let didSuccessfullyProcess = false
 | 
					  let didSuccessfullyProcess: boolean // TODO: fix this: this no longer is truthful, returns true or false if there was not a JS error
 | 
				
			||||||
  if (existingProcessedArea.id !== areaId) didSuccessfullyProcess = await RequestAddProcessedArea(newProcessedArea)
 | 
					  try {
 | 
				
			||||||
 | 
					    if (existingProcessedArea.id !== areaId) await RequestAddProcessedArea(newProcessedArea)
 | 
				
			||||||
    else await RequestUpdateProcessedArea(newProcessedArea)
 | 
					    else await RequestUpdateProcessedArea(newProcessedArea)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    saveProcessedText()
 | 
					    saveProcessedText()
 | 
				
			||||||
 | 
					    didSuccessfullyProcess = true
 | 
				
			||||||
 | 
					  } catch (err) {
 | 
				
			||||||
 | 
					    didSuccessfullyProcess = false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return didSuccessfullyProcess
 | 
					  return didSuccessfullyProcess
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										103
									
								
								frontend/useCases/processImageRect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								frontend/useCases/processImageRect.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					import { PSM, createScheduler, createWorker } from 'tesseract.js'
 | 
				
			||||||
 | 
					import { GetDocumentById, RequestAddArea, RequestAddProcessedArea } from '../wailsjs/wailsjs/go/ipc/Channel'
 | 
				
			||||||
 | 
					import loadImage from './loadImage'
 | 
				
			||||||
 | 
					import { entities } from '../wailsjs/wailsjs/go/models'
 | 
				
			||||||
 | 
					import { saveProcessedText } from './saveData'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type rect = {
 | 
				
			||||||
 | 
					  startX: number,
 | 
				
			||||||
 | 
					  endX: number,
 | 
				
			||||||
 | 
					  startY: number,
 | 
				
			||||||
 | 
					  endY: number,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const processImageRect = async (documentId: string, rectangle: rect): Promise<entities.ProcessedArea[]> => {
 | 
				
			||||||
 | 
					  const foundDocument = await GetDocumentById(documentId)
 | 
				
			||||||
 | 
					  const { path, defaultLanguage } = foundDocument
 | 
				
			||||||
 | 
					  if (!path || !defaultLanguage) return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const processLanguage = defaultLanguage.processCode
 | 
				
			||||||
 | 
					  const imageData = await loadImage(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let workerOptions: Partial<Tesseract.WorkerOptions> = {}
 | 
				
			||||||
 | 
					  if (foundDocument.defaultLanguage.isBundledCustom) {
 | 
				
			||||||
 | 
					    workerOptions = {
 | 
				
			||||||
 | 
					      langPath: '/customLanguages',
 | 
				
			||||||
 | 
					      gzip: false,
 | 
				
			||||||
 | 
					      // logger: m => console.log(m)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const worker = await createWorker(workerOptions)
 | 
				
			||||||
 | 
					  await worker.loadLanguage(processLanguage)
 | 
				
			||||||
 | 
					  await worker.initialize(processLanguage)
 | 
				
			||||||
 | 
					  await worker.setParameters({
 | 
				
			||||||
 | 
					    tessedit_pageseg_mode: PSM.AUTO_OSD,
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const scheduler = createScheduler()
 | 
				
			||||||
 | 
					  scheduler.addWorker(worker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const result = await scheduler.addJob('recognize', imageData, {
 | 
				
			||||||
 | 
					    rectangle: {
 | 
				
			||||||
 | 
					      left: rectangle.startX,
 | 
				
			||||||
 | 
					      top: rectangle.startY,
 | 
				
			||||||
 | 
					      width: rectangle.endX - rectangle.startX,
 | 
				
			||||||
 | 
					      height: rectangle.endY - rectangle.startY,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const addAreaRequests = result.data.paragraphs.map(async (p: any) => {
 | 
				
			||||||
 | 
					    const defaultAreaName = p.lines[0]?.words[0]?.text || ''
 | 
				
			||||||
 | 
					    const area = await RequestAddArea(
 | 
				
			||||||
 | 
					      documentId,
 | 
				
			||||||
 | 
					      new entities.Area({
 | 
				
			||||||
 | 
					        name: defaultAreaName,
 | 
				
			||||||
 | 
					        startX: p.bbox.x0,
 | 
				
			||||||
 | 
					        endX: p.bbox.x1,
 | 
				
			||||||
 | 
					        startY: p.bbox.y0,
 | 
				
			||||||
 | 
					        endY: p.bbox.y1,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const processedArea = await RequestAddProcessedArea(new entities.ProcessedArea({
 | 
				
			||||||
 | 
					      id: area.id,
 | 
				
			||||||
 | 
					      documentId,
 | 
				
			||||||
 | 
					      order: area.order,
 | 
				
			||||||
 | 
					      fullText: p.text,
 | 
				
			||||||
 | 
					      lines: p.lines.map((l: any) => new entities.ProcessedLine({
 | 
				
			||||||
 | 
					        fullText: l.text,
 | 
				
			||||||
 | 
					        words: l.words.map((w: any) => new entities.ProcessedWord({
 | 
				
			||||||
 | 
					          areaId: area.id,
 | 
				
			||||||
 | 
					          fullText: w.text,
 | 
				
			||||||
 | 
					          direction: w.direction,
 | 
				
			||||||
 | 
					          confidence: w.confidence,
 | 
				
			||||||
 | 
					          boundingBox: new entities.ProcessedBoundingBox({
 | 
				
			||||||
 | 
					            x0: w.bbox.x0,
 | 
				
			||||||
 | 
					            y0: w.bbox.y0,
 | 
				
			||||||
 | 
					            x1: w.bbox.x1,
 | 
				
			||||||
 | 
					            y1: w.bbox.y1,
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					          symbols: w.symbols.map((s: any) => new entities.ProcessedSymbol({
 | 
				
			||||||
 | 
					            fullText: s.text,
 | 
				
			||||||
 | 
					            confidence: s.confidence,
 | 
				
			||||||
 | 
					            boundingBox: new entities.ProcessedBoundingBox({
 | 
				
			||||||
 | 
					              x0: s.bbox.x0,
 | 
				
			||||||
 | 
					              y0: s.bbox.y0,
 | 
				
			||||||
 | 
					              x1: s.bbox.x1,
 | 
				
			||||||
 | 
					              y1: s.bbox.y1,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					          }))
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					    }))
 | 
				
			||||||
 | 
					    return processedArea
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const addAreaResponses = await Promise.allSettled(addAreaRequests)
 | 
				
			||||||
 | 
					  const areas = addAreaResponses.filter((val): val is PromiseFulfilledResult<entities.ProcessedArea> => val.status === 'fulfilled').map(val => val.value)
 | 
				
			||||||
 | 
					  await saveProcessedText()
 | 
				
			||||||
 | 
					  return areas
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default processImageRect
 | 
				
			||||||
@ -1,4 +1,7 @@
 | 
				
			|||||||
import { RequestSaveDocumentCollection, RequestSaveGroupCollection, RequestSaveLocalUserProcessedMarkdownCollection, RequestSaveProcessedTextCollection } from '../wailsjs/wailsjs/go/ipc/Channel'
 | 
					import { RequestSaveDocumentCollection, RequestSaveGroupCollection,
 | 
				
			||||||
 | 
					  RequestSaveLocalUserProcessedMarkdownCollection,
 | 
				
			||||||
 | 
					  RequestSaveProcessedTextCollection, RequestSaveContextGroupCollection
 | 
				
			||||||
 | 
					} from '../wailsjs/wailsjs/go/ipc/Channel'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const saveDocuments = async () => {
 | 
					const saveDocuments = async () => {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@ -36,9 +39,19 @@ const saveUserProcessedMarkdown = async () => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const saveContextGroups = async () => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const sucessfulSave = await RequestSaveContextGroupCollection()
 | 
				
			||||||
 | 
					    if (!sucessfulSave) console.error('Could not save ContextGroupCollection')
 | 
				
			||||||
 | 
					  } catch (err) {
 | 
				
			||||||
 | 
					    console.error('Could not save ContextGroupCollection: ', err)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  saveDocuments,
 | 
					  saveDocuments,
 | 
				
			||||||
  saveGroups,
 | 
					  saveGroups,
 | 
				
			||||||
  saveProcessedText,
 | 
					  saveProcessedText,
 | 
				
			||||||
  saveUserProcessedMarkdown,
 | 
					  saveUserProcessedMarkdown,
 | 
				
			||||||
 | 
					  saveContextGroups,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
									
									
									
									
										vendored
									
									
								
							@ -23,6 +23,8 @@ export function GetProcessedAreasByDocumentId(arg1:string):Promise<Array<entitie
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export function GetProjectByName(arg1:string):Promise<entities.Project>;
 | 
					export function GetProjectByName(arg1:string):Promise<entities.Project>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GetSerializedContextGroups():Promise<Array<entities.SerializedLinkedProcessedArea>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function GetSupportedLanguages():Promise<Array<entities.Language>>;
 | 
					export function GetSupportedLanguages():Promise<Array<entities.Language>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function GetUserMarkdownByDocumentId(arg1:string):Promise<entities.UserMarkdown>;
 | 
					export function GetUserMarkdownByDocumentId(arg1:string):Promise<entities.UserMarkdown>;
 | 
				
			||||||
@ -33,7 +35,7 @@ export function RequestAddDocument(arg1:string,arg2:string):Promise<entities.Doc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export function RequestAddDocumentGroup(arg1:string):Promise<entities.Group>;
 | 
					export function RequestAddDocumentGroup(arg1:string):Promise<entities.Group>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestAddProcessedArea(arg1:entities.ProcessedArea):Promise<boolean>;
 | 
					export function RequestAddProcessedArea(arg1:entities.ProcessedArea):Promise<entities.ProcessedArea>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestChangeAreaOrder(arg1:string,arg2:number):Promise<entities.Document>;
 | 
					export function RequestChangeAreaOrder(arg1:string,arg2:number):Promise<entities.Document>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -43,7 +45,7 @@ export function RequestChangeSessionProjectByName(arg1:string):Promise<boolean>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export function RequestChooseUserAvatar():Promise<string>;
 | 
					export function RequestChooseUserAvatar():Promise<string>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestConnectAreaAsTailToNode(arg1:string,arg2:string):Promise<boolean>;
 | 
					export function RequestConnectProcessedAreas(arg1:string,arg2:string):Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestDeleteAreaById(arg1:string):Promise<boolean>;
 | 
					export function RequestDeleteAreaById(arg1:string):Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,6 +53,10 @@ export function RequestDeleteDocumentAndChildren(arg1:string):Promise<boolean>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export function RequestDeleteProcessedAreaById(arg1:string):Promise<boolean>;
 | 
					export function RequestDeleteProcessedAreaById(arg1:string):Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RequestDisconnectProcessedAreas(arg1:string,arg2:string):Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RequestSaveContextGroupCollection():Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestSaveDocumentCollection():Promise<boolean>;
 | 
					export function RequestSaveDocumentCollection():Promise<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestSaveGroupCollection():Promise<boolean>;
 | 
					export function RequestSaveGroupCollection():Promise<boolean>;
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,10 @@ export function GetProjectByName(arg1) {
 | 
				
			|||||||
  return window['go']['ipc']['Channel']['GetProjectByName'](arg1);
 | 
					  return window['go']['ipc']['Channel']['GetProjectByName'](arg1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function GetSerializedContextGroups() {
 | 
				
			||||||
 | 
					  return window['go']['ipc']['Channel']['GetSerializedContextGroups']();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function GetSupportedLanguages() {
 | 
					export function GetSupportedLanguages() {
 | 
				
			||||||
  return window['go']['ipc']['Channel']['GetSupportedLanguages']();
 | 
					  return window['go']['ipc']['Channel']['GetSupportedLanguages']();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -82,8 +86,8 @@ export function RequestChooseUserAvatar() {
 | 
				
			|||||||
  return window['go']['ipc']['Channel']['RequestChooseUserAvatar']();
 | 
					  return window['go']['ipc']['Channel']['RequestChooseUserAvatar']();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestConnectAreaAsTailToNode(arg1, arg2) {
 | 
					export function RequestConnectProcessedAreas(arg1, arg2) {
 | 
				
			||||||
  return window['go']['ipc']['Channel']['RequestConnectAreaAsTailToNode'](arg1, arg2);
 | 
					  return window['go']['ipc']['Channel']['RequestConnectProcessedAreas'](arg1, arg2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestDeleteAreaById(arg1) {
 | 
					export function RequestDeleteAreaById(arg1) {
 | 
				
			||||||
@ -98,6 +102,14 @@ export function RequestDeleteProcessedAreaById(arg1) {
 | 
				
			|||||||
  return window['go']['ipc']['Channel']['RequestDeleteProcessedAreaById'](arg1);
 | 
					  return window['go']['ipc']['Channel']['RequestDeleteProcessedAreaById'](arg1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RequestDisconnectProcessedAreas(arg1, arg2) {
 | 
				
			||||||
 | 
					  return window['go']['ipc']['Channel']['RequestDisconnectProcessedAreas'](arg1, arg2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function RequestSaveContextGroupCollection() {
 | 
				
			||||||
 | 
					  return window['go']['ipc']['Channel']['RequestSaveContextGroupCollection']();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function RequestSaveDocumentCollection() {
 | 
					export function RequestSaveDocumentCollection() {
 | 
				
			||||||
  return window['go']['ipc']['Channel']['RequestSaveDocumentCollection']();
 | 
					  return window['go']['ipc']['Channel']['RequestSaveDocumentCollection']();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -422,6 +422,22 @@ export namespace entities {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						export class SerializedLinkedProcessedArea {
 | 
				
			||||||
 | 
						    areaId: string;
 | 
				
			||||||
 | 
						    previousId: string;
 | 
				
			||||||
 | 
						    nextId: string;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    static createFrom(source: any = {}) {
 | 
				
			||||||
 | 
						        return new SerializedLinkedProcessedArea(source);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    constructor(source: any = {}) {
 | 
				
			||||||
 | 
						        if ('string' === typeof source) source = JSON.parse(source);
 | 
				
			||||||
 | 
						        this.areaId = source["areaId"];
 | 
				
			||||||
 | 
						        this.previousId = source["previousId"];
 | 
				
			||||||
 | 
						        this.nextId = source["nextId"];
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	export class Session {
 | 
						export class Session {
 | 
				
			||||||
	    project: Project;
 | 
						    project: Project;
 | 
				
			||||||
	    organization: Organization;
 | 
						    organization: Organization;
 | 
				
			||||||
@ -481,6 +497,7 @@ export namespace ipc {
 | 
				
			|||||||
	export class GetDocumentsResponse {
 | 
						export class GetDocumentsResponse {
 | 
				
			||||||
	    documents: entities.Document[];
 | 
						    documents: entities.Document[];
 | 
				
			||||||
	    groups: entities.Group[];
 | 
						    groups: entities.Group[];
 | 
				
			||||||
 | 
						    contextGroups: entities.SerializedLinkedProcessedArea[];
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	    static createFrom(source: any = {}) {
 | 
						    static createFrom(source: any = {}) {
 | 
				
			||||||
	        return new GetDocumentsResponse(source);
 | 
						        return new GetDocumentsResponse(source);
 | 
				
			||||||
@ -490,6 +507,7 @@ export namespace ipc {
 | 
				
			|||||||
	        if ('string' === typeof source) source = JSON.parse(source);
 | 
						        if ('string' === typeof source) source = JSON.parse(source);
 | 
				
			||||||
	        this.documents = this.convertValues(source["documents"], entities.Document);
 | 
						        this.documents = this.convertValues(source["documents"], entities.Document);
 | 
				
			||||||
	        this.groups = this.convertValues(source["groups"], entities.Group);
 | 
						        this.groups = this.convertValues(source["groups"], entities.Group);
 | 
				
			||||||
 | 
						        this.contextGroups = this.convertValues(source["contextGroups"], entities.SerializedLinkedProcessedArea);
 | 
				
			||||||
	    }
 | 
						    }
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
		convertValues(a: any, classs: any, asMap: boolean = false): any {
 | 
							convertValues(a: any, classs: any, asMap: boolean = false): any {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +1,68 @@
 | 
				
			|||||||
package ipc
 | 
					package ipc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						contextGroup "textualize/core/ContextGroup"
 | 
				
			||||||
	document "textualize/core/Document"
 | 
						document "textualize/core/Document"
 | 
				
			||||||
	"textualize/entities"
 | 
						"textualize/entities"
 | 
				
			||||||
 | 
						"textualize/storage"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) RequestConnectAreaAsTailToNode(tailId string, headId string) bool {
 | 
					func (c *Channel) RequestDisconnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool {
 | 
				
			||||||
	processedAreaOfTail := document.GetProcessedAreaCollection().GetAreaById(tailId)
 | 
						contextGroupCollection := contextGroup.GetContextGroupCollection()
 | 
				
			||||||
	if processedAreaOfTail == nil {
 | 
					
 | 
				
			||||||
		return false
 | 
						wasSuccessfulDisconnect := contextGroupCollection.DisconnectProcessedAreas(ancestorAreaId, descendantAreaId)
 | 
				
			||||||
 | 
						if wasSuccessfulDisconnect {
 | 
				
			||||||
 | 
							wasSuccessfulWrite := c.RequestSaveContextGroupCollection()
 | 
				
			||||||
 | 
							return wasSuccessfulWrite
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	processedAreaOfHead := document.GetProcessedAreaCollection().GetAreaById(headId)
 | 
					 | 
				
			||||||
	if processedAreaOfHead == nil {
 | 
					 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
	}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	entities.GetContextGroupCollection().ConnectAreaAsTailToNode(*processedAreaOfTail, *processedAreaOfHead)
 | 
					/*
 | 
				
			||||||
 | 
					If a connection already exists, then this method will default to disconnecting the two areas.
 | 
				
			||||||
	return true
 | 
					*/
 | 
				
			||||||
 | 
					func (c *Channel) RequestConnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool {
 | 
				
			||||||
 | 
						contextGroupCollection := contextGroup.GetContextGroupCollection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						doesContextGroupAlreadyExist := contextGroupCollection.DoesGroupExistBetweenProcessedAreas(ancestorAreaId, descendantAreaId)
 | 
				
			||||||
 | 
						if doesContextGroupAlreadyExist {
 | 
				
			||||||
 | 
							return c.RequestDisconnectProcessedAreas(ancestorAreaId, descendantAreaId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						processedAreaCollection := document.GetProcessedAreaCollection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ancestorArea := processedAreaCollection.GetAreaById(ancestorAreaId)
 | 
				
			||||||
 | 
						descendantArea := processedAreaCollection.GetAreaById(descendantAreaId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wasSuccessfulConnect := contextGroupCollection.ConnectProcessedAreas(*ancestorArea, *descendantArea)
 | 
				
			||||||
 | 
						if wasSuccessfulConnect {
 | 
				
			||||||
 | 
							wasSuccessfulWrite := c.RequestSaveContextGroupCollection()
 | 
				
			||||||
 | 
							return wasSuccessfulWrite
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Channel) GetSerializedContextGroups() []entities.SerializedLinkedProcessedArea {
 | 
				
			||||||
 | 
						contextGroupCollection := contextGroup.GetContextGroupCollection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serializedContextGroups := make([]entities.SerializedLinkedProcessedArea, 0)
 | 
				
			||||||
 | 
						for _, group := range contextGroupCollection.Groups {
 | 
				
			||||||
 | 
							serializedContextGroups = append(serializedContextGroups, group.Serialize()...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return serializedContextGroups
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Channel) RequestSaveContextGroupCollection() bool {
 | 
				
			||||||
 | 
						contextGroupCollection := contextGroup.GetContextGroupCollection()
 | 
				
			||||||
 | 
						projectName := c.GetCurrentSession().Project.Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serializedContextGroups := make([]entities.SerializedLinkedProcessedArea, 0)
 | 
				
			||||||
 | 
						for _, group := range contextGroupCollection.Groups {
 | 
				
			||||||
 | 
							serializedContextGroups = append(serializedContextGroups, group.Serialize()...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						successfulWrite := storage.GetDriver().WriteContextGroupCollection(serializedContextGroups, projectName)
 | 
				
			||||||
 | 
						return successfulWrite
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ import (
 | 
				
			|||||||
type GetDocumentsResponse struct {
 | 
					type GetDocumentsResponse struct {
 | 
				
			||||||
	Documents     []entities.Document                      `json:"documents"`
 | 
						Documents     []entities.Document                      `json:"documents"`
 | 
				
			||||||
	Groups        []entities.Group                         `json:"groups"`
 | 
						Groups        []entities.Group                         `json:"groups"`
 | 
				
			||||||
 | 
						ContextGroups []entities.SerializedLinkedProcessedArea `json:"contextGroups"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) GetDocumentById(id string) entities.Document {
 | 
					func (c *Channel) GetDocumentById(id string) entities.Document {
 | 
				
			||||||
@ -26,10 +27,12 @@ func (c *Channel) GetDocumentById(id string) entities.Document {
 | 
				
			|||||||
func (c *Channel) GetDocuments() GetDocumentsResponse {
 | 
					func (c *Channel) GetDocuments() GetDocumentsResponse {
 | 
				
			||||||
	documents := document.GetDocumentCollection().Documents
 | 
						documents := document.GetDocumentCollection().Documents
 | 
				
			||||||
	groups := document.GetGroupCollection().Groups
 | 
						groups := document.GetGroupCollection().Groups
 | 
				
			||||||
 | 
						contextGroups := c.GetSerializedContextGroups()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	response := GetDocumentsResponse{
 | 
						response := GetDocumentsResponse{
 | 
				
			||||||
		Groups:        make([]entities.Group, 0),
 | 
							Groups:        make([]entities.Group, 0),
 | 
				
			||||||
		Documents:     make([]entities.Document, 0),
 | 
							Documents:     make([]entities.Document, 0),
 | 
				
			||||||
 | 
							ContextGroups: contextGroups,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, d := range documents {
 | 
						for _, d := range documents {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
package ipc
 | 
					package ipc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	document "textualize/core/Document"
 | 
						document "textualize/core/Document"
 | 
				
			||||||
	"textualize/entities"
 | 
						"textualize/entities"
 | 
				
			||||||
@ -35,7 +34,7 @@ func (c *Channel) GetProcessedAreasByDocumentId(id string) []entities.ProcessedA
 | 
				
			|||||||
	return sortedAreas
 | 
						return sortedAreas
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea) bool {
 | 
					func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea) entities.ProcessedArea {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for lineIndex, line := range processedArea.Lines {
 | 
						for lineIndex, line := range processedArea.Lines {
 | 
				
			||||||
		for wordIndex, word := range line.Words {
 | 
							for wordIndex, word := range line.Words {
 | 
				
			||||||
@ -46,7 +45,7 @@ func (c *Channel) RequestAddProcessedArea(processedArea entities.ProcessedArea)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	document.GetProcessedAreaCollection().AddProcessedArea(processedArea)
 | 
						document.GetProcessedAreaCollection().AddProcessedArea(processedArea)
 | 
				
			||||||
	return true
 | 
						return *document.GetProcessedAreaCollection().GetAreaById(processedArea.Id)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) RequestDeleteProcessedAreaById(id string) bool {
 | 
					func (c *Channel) RequestDeleteProcessedAreaById(id string) bool {
 | 
				
			||||||
@ -75,9 +74,6 @@ func (c *Channel) RequestDeleteProcessedAreaById(id string) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) RequestUpdateProcessedArea(updatedProcessedArea entities.ProcessedArea) bool {
 | 
					func (c *Channel) RequestUpdateProcessedArea(updatedProcessedArea entities.ProcessedArea) bool {
 | 
				
			||||||
	fmt.Println("updatedProcessedArea")
 | 
					 | 
				
			||||||
	fmt.Println(&updatedProcessedArea)
 | 
					 | 
				
			||||||
	fmt.Println()
 | 
					 | 
				
			||||||
	if updatedProcessedArea.Id == "" {
 | 
						if updatedProcessedArea.Id == "" {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -87,14 +83,13 @@ func (c *Channel) RequestUpdateProcessedArea(updatedProcessedArea entities.Proce
 | 
				
			|||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	successfulAdd := c.RequestAddProcessedArea(updatedProcessedArea)
 | 
						addedProcessedArea := c.RequestAddProcessedArea(updatedProcessedArea)
 | 
				
			||||||
	if !successfulAdd {
 | 
						return addedProcessedArea.Id != ""
 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fmt.Println("document.GetProcessedAreaCollection().GetAreaById(updatedProcessedArea.Id)")
 | 
						// if addedProcessedArea.Id != "" {
 | 
				
			||||||
	fmt.Println(document.GetProcessedAreaCollection().GetAreaById(updatedProcessedArea.Id))
 | 
						// 	return false
 | 
				
			||||||
	return true
 | 
						// }
 | 
				
			||||||
 | 
						// return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Channel) RequestUpdateProcessedWordById(wordId string, newTextValue string) bool {
 | 
					func (c *Channel) RequestUpdateProcessedWordById(wordId string, newTextValue string) bool {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ package ipc
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	app "textualize/core/App"
 | 
						app "textualize/core/App"
 | 
				
			||||||
	consts "textualize/core/Consts"
 | 
						consts "textualize/core/Consts"
 | 
				
			||||||
 | 
						contextGroup "textualize/core/ContextGroup"
 | 
				
			||||||
	document "textualize/core/Document"
 | 
						document "textualize/core/Document"
 | 
				
			||||||
	session "textualize/core/Session"
 | 
						session "textualize/core/Session"
 | 
				
			||||||
	"textualize/entities"
 | 
						"textualize/entities"
 | 
				
			||||||
@ -144,6 +145,7 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	session.GetInstance().Project = foundProject
 | 
						session.GetInstance().Project = foundProject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Documents
 | 
				
			||||||
	localDocumentCollection := storageDriver.ReadDocumentCollection(projectName)
 | 
						localDocumentCollection := storageDriver.ReadDocumentCollection(projectName)
 | 
				
			||||||
	documentCount := len(localDocumentCollection.Documents)
 | 
						documentCount := len(localDocumentCollection.Documents)
 | 
				
			||||||
	readableDocuments := make([]document.Entity, documentCount)
 | 
						readableDocuments := make([]document.Entity, documentCount)
 | 
				
			||||||
@ -155,6 +157,7 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
				
			|||||||
		ProjectId: foundProject.Id,
 | 
							ProjectId: foundProject.Id,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Groups
 | 
				
			||||||
	localGroupsCollection := storageDriver.ReadGroupCollection(projectName)
 | 
						localGroupsCollection := storageDriver.ReadGroupCollection(projectName)
 | 
				
			||||||
	groupCount := len(localGroupsCollection.Groups)
 | 
						groupCount := len(localGroupsCollection.Groups)
 | 
				
			||||||
	readableGroups := make([]entities.Group, groupCount)
 | 
						readableGroups := make([]entities.Group, groupCount)
 | 
				
			||||||
@ -167,6 +170,10 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
				
			|||||||
		Groups:    readableGroups,
 | 
							Groups:    readableGroups,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Context Groups
 | 
				
			||||||
 | 
						localSerializedContextGroups := storageDriver.ReadContextGroupCollection(projectName)
 | 
				
			||||||
 | 
						contextGroup.SetContextGroupCollectionBySerialized(localSerializedContextGroups)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Processed Texts
 | 
						// Processed Texts
 | 
				
			||||||
	localProcessedAreaCollection := storageDriver.ReadProcessedTextCollection(projectName)
 | 
						localProcessedAreaCollection := storageDriver.ReadProcessedTextCollection(projectName)
 | 
				
			||||||
	areaCount := len(localProcessedAreaCollection.Areas)
 | 
						areaCount := len(localProcessedAreaCollection.Areas)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								storage/Local/ContextGroupDriver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								storage/Local/ContextGroupDriver.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"textualize/entities"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d LocalDriver) WriteContextGroupCollection(serializedContextGroups []entities.SerializedLinkedProcessedArea, projectName string) bool {
 | 
				
			||||||
 | 
						jsonData, _ := json.MarshalIndent(serializedContextGroups, "", " ")
 | 
				
			||||||
 | 
						writeError := WriteDataToAppDir(jsonData, "/projects/"+projectName+"/", "ContextGroups.json")
 | 
				
			||||||
 | 
						return writeError == nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d LocalDriver) ReadContextGroupCollection(projectName string) []entities.SerializedLinkedProcessedArea {
 | 
				
			||||||
 | 
						contextGroupCollectionData := make([]entities.SerializedLinkedProcessedArea, 0)
 | 
				
			||||||
 | 
						readError := AssignFileDataToStruct("/projects/"+projectName+"/ContextGroups.json", &contextGroupCollectionData)
 | 
				
			||||||
 | 
						if readError != nil {
 | 
				
			||||||
 | 
							return make([]entities.SerializedLinkedProcessedArea, 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return contextGroupCollectionData
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -19,6 +19,8 @@ type Driver interface {
 | 
				
			|||||||
	ReadProcessedTextCollection(string) entities.ProcessedTextCollection
 | 
						ReadProcessedTextCollection(string) entities.ProcessedTextCollection
 | 
				
			||||||
	WriteProcessedUserMarkdownCollection(entities.ProcessedUserMarkdownCollection, string) bool
 | 
						WriteProcessedUserMarkdownCollection(entities.ProcessedUserMarkdownCollection, string) bool
 | 
				
			||||||
	ReadProcessedUserMarkdownCollection(string) entities.ProcessedUserMarkdownCollection
 | 
						ReadProcessedUserMarkdownCollection(string) entities.ProcessedUserMarkdownCollection
 | 
				
			||||||
 | 
						WriteContextGroupCollection([]entities.SerializedLinkedProcessedArea, string) bool
 | 
				
			||||||
 | 
						ReadContextGroupCollection(string) []entities.SerializedLinkedProcessedArea
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var driverInstance Driver
 | 
					var driverInstance Driver
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user