Refactor Context Groups & Area Detection #4
							
								
								
									
										112
									
								
								core/ContextGroup/ContextGroupCollection.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								core/ContextGroup/ContextGroupCollection.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
			
		||||
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) 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndependentTranslatedWord struct {
 | 
			
		||||
@ -15,43 +13,57 @@ type IndependentTranslatedWord struct {
 | 
			
		||||
 | 
			
		||||
type LinkedProcessedArea struct {
 | 
			
		||||
	Area     ProcessedArea
 | 
			
		||||
	previous *LinkedProcessedArea
 | 
			
		||||
	next     *LinkedProcessedArea
 | 
			
		||||
	Previous *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 {
 | 
			
		||||
	head *LinkedProcessedArea
 | 
			
		||||
	tail *LinkedProcessedArea
 | 
			
		||||
	Id              string
 | 
			
		||||
	DocumentId      string
 | 
			
		||||
	TranslationText string
 | 
			
		||||
	Head            *LinkedProcessedArea
 | 
			
		||||
	Tail            *LinkedProcessedArea
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *LinkedAreaList) First() *LinkedProcessedArea {
 | 
			
		||||
	return l.head
 | 
			
		||||
	return l.Head
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (linkedProcessedWord *LinkedProcessedArea) Next() *LinkedProcessedArea {
 | 
			
		||||
	return linkedProcessedWord.next
 | 
			
		||||
func (linkedProcessedWord *LinkedProcessedArea) GetNext() *LinkedProcessedArea {
 | 
			
		||||
	return linkedProcessedWord.Next
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (linkedProcessedWord *LinkedProcessedArea) Prev() *LinkedProcessedArea {
 | 
			
		||||
	return linkedProcessedWord.previous
 | 
			
		||||
func (linkedProcessedWord *LinkedProcessedArea) GetPrevious() *LinkedProcessedArea {
 | 
			
		||||
	return linkedProcessedWord.Previous
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create new node with value
 | 
			
		||||
func (l *LinkedAreaList) Push(processedArea ProcessedArea) *LinkedAreaList {
 | 
			
		||||
	n := &LinkedProcessedArea{Area: processedArea}
 | 
			
		||||
	if l.head == nil {
 | 
			
		||||
		l.head = n // First node
 | 
			
		||||
	if l.Head == nil {
 | 
			
		||||
		l.Head = n // First node
 | 
			
		||||
	} else {
 | 
			
		||||
		l.tail.next = n     // Add after prev last node
 | 
			
		||||
		n.previous = l.tail // Link back to prev last node
 | 
			
		||||
		l.Tail.Next = n     // Add after 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *LinkedAreaList) Find(id string) *LinkedProcessedArea {
 | 
			
		||||
	found := false
 | 
			
		||||
	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 {
 | 
			
		||||
			found = true
 | 
			
		||||
			ret = n
 | 
			
		||||
@ -59,16 +71,17 @@ func (l *LinkedAreaList) Find(id string) *LinkedProcessedArea {
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *LinkedAreaList) Delete(id string) bool {
 | 
			
		||||
	success := false
 | 
			
		||||
	node2del := l.Find(id)
 | 
			
		||||
	if node2del != nil {
 | 
			
		||||
		fmt.Println("Delete - FOUND: ", id)
 | 
			
		||||
		prev_node := node2del.previous
 | 
			
		||||
		next_node := node2del.next
 | 
			
		||||
		prev_node := node2del.Previous
 | 
			
		||||
		next_node := node2del.Next
 | 
			
		||||
		// Remove this node
 | 
			
		||||
		prev_node.next = node2del.next
 | 
			
		||||
		next_node.previous = node2del.previous
 | 
			
		||||
		prev_node.Next = node2del.Next
 | 
			
		||||
		next_node.Previous = node2del.Previous
 | 
			
		||||
		success = true
 | 
			
		||||
	}
 | 
			
		||||
	return success
 | 
			
		||||
@ -78,86 +91,83 @@ var errEmpty = errors.New("ERROR - List is empty")
 | 
			
		||||
 | 
			
		||||
// Pop last item from list
 | 
			
		||||
func (l *LinkedAreaList) Pop() (processedArea ProcessedArea, err error) {
 | 
			
		||||
	if l.tail == nil {
 | 
			
		||||
	if l.Tail == nil {
 | 
			
		||||
		err = errEmpty
 | 
			
		||||
	} else {
 | 
			
		||||
		processedArea = l.tail.Area
 | 
			
		||||
		l.tail = l.tail.previous
 | 
			
		||||
		if l.tail == nil {
 | 
			
		||||
			l.head = nil
 | 
			
		||||
		processedArea = l.Tail.Area
 | 
			
		||||
		l.Tail = l.Tail.Previous
 | 
			
		||||
		if l.Tail == nil {
 | 
			
		||||
			l.Head = nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return processedArea, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ContextGroup struct { // TODO: possibly remove this and expand the LinkedAreaList struct instead
 | 
			
		||||
	Id              string
 | 
			
		||||
	DocumentId      string
 | 
			
		||||
	LinkedAreaList  LinkedAreaList
 | 
			
		||||
	TranslationText string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ContextGroupCollection struct { // TODO: these methods should live in core not entitites
 | 
			
		||||
	Groups []ContextGroup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
func (l *LinkedAreaList) InsertAfter(id string, processedArea ProcessedArea) bool {
 | 
			
		||||
	found := false
 | 
			
		||||
	for n := l.First(); n != nil && !found; n = n.GetNext() {
 | 
			
		||||
		if n.Area.Id == id {
 | 
			
		||||
			found = true
 | 
			
		||||
			newNode := &LinkedProcessedArea{Area: processedArea}
 | 
			
		||||
			newNode.Next = n.Next
 | 
			
		||||
			newNode.Previous = n
 | 
			
		||||
			n.Next = newNode
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return foundContextGroup
 | 
			
		||||
	return found
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (collection *ContextGroupCollection) CreateContextGroupFromProcessedArea(area ProcessedArea) bool {
 | 
			
		||||
	fmt.Println("CreateContextGroupFromProcessedArea")
 | 
			
		||||
 | 
			
		||||
	newLinkedAreaList := LinkedAreaList{}
 | 
			
		||||
	newLinkedAreaList.Push(area)
 | 
			
		||||
 | 
			
		||||
	newContextGroup := ContextGroup{
 | 
			
		||||
		Id:             uuid.NewString(),
 | 
			
		||||
		DocumentId:     area.DocumentId,
 | 
			
		||||
		LinkedAreaList: newLinkedAreaList,
 | 
			
		||||
func (l *LinkedAreaList) InsertBefore(id string, processedArea ProcessedArea) bool {
 | 
			
		||||
	found := false
 | 
			
		||||
	for n := l.First(); n != nil && !found; n = n.GetNext() {
 | 
			
		||||
		if n.Area.Id == id {
 | 
			
		||||
			found = true
 | 
			
		||||
			newNode := &LinkedProcessedArea{Area: processedArea}
 | 
			
		||||
			newNode.Next = n
 | 
			
		||||
			newNode.Previous = n.Previous
 | 
			
		||||
			n.Previous = newNode
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	collection.Groups = append(collection.Groups, newContextGroup)
 | 
			
		||||
	return true
 | 
			
		||||
	return found
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: completely rework this linked list and the collection
 | 
			
		||||
func (collection *ContextGroupCollection) ConnectAreaAsTailToNode(tailArea ProcessedArea, headArea ProcessedArea) bool {
 | 
			
		||||
	headNodeContextGroup := collection.FindContextGroupByNodeId(headArea.Id)
 | 
			
		||||
func (l *LinkedAreaList) Serialize() []SerializedLinkedProcessedArea {
 | 
			
		||||
	var serialized []SerializedLinkedProcessedArea
 | 
			
		||||
	for n := l.First(); n != nil; n = n.GetNext() {
 | 
			
		||||
		areaId := n.Area.Id
 | 
			
		||||
		previousId := ""
 | 
			
		||||
		if n.Previous != nil {
 | 
			
		||||
			previousId = n.Previous.Area.Id
 | 
			
		||||
		}
 | 
			
		||||
		nextId := ""
 | 
			
		||||
		if n.Next != nil {
 | 
			
		||||
			nextId = n.Next.Area.Id
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if headNodeContextGroup == nil {
 | 
			
		||||
		collection.CreateContextGroupFromProcessedArea(headArea)
 | 
			
		||||
		headNodeContextGroup = collection.FindContextGroupByNodeId(headArea.Id)
 | 
			
		||||
		serialized = append(serialized, SerializedLinkedProcessedArea{
 | 
			
		||||
			AreaId:     areaId,
 | 
			
		||||
			PreviousId: previousId,
 | 
			
		||||
			NextId:     nextId,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	headNode := headNodeContextGroup.LinkedAreaList.Find(headArea.Id)
 | 
			
		||||
	headNode.next = &LinkedProcessedArea{
 | 
			
		||||
		Area:     tailArea,
 | 
			
		||||
		previous: headNode,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
	return serialized
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,71 @@
 | 
			
		||||
'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}
 | 
			
		||||
      />
 | 
			
		||||
    })
 | 
			
		||||
    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 { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
			
		||||
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[] }
 | 
			
		||||
const ConnectionPoints = (props: Props) => {
 | 
			
		||||
  const { isLinkAreaContextsVisible, scale, startingContextConnection, setStartingContextConnection } = useStage()
 | 
			
		||||
  const { requestConnectProcessedAreas } = useProject()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  const handleContextAreaMouseDown = (e: KonvaEventObject<MouseEvent>) => {
 | 
			
		||||
  const handleContextAreaMouseDown = async (e: KonvaEventObject<MouseEvent>) => {
 | 
			
		||||
    e.cancelBubble = true
 | 
			
		||||
    const clickedConnectionPoint = {
 | 
			
		||||
      isHead: e.currentTarget.attrs.isHead,
 | 
			
		||||
@ -24,10 +24,15 @@ const ConnectionPoints = (props: Props) => {
 | 
			
		||||
      || clickedConnectionPoint.areaId === startingContextConnection.areaId)
 | 
			
		||||
      return setStartingContextConnection(null)
 | 
			
		||||
 | 
			
		||||
    console.log('connected points', startingContextConnection, clickedConnectionPoint)
 | 
			
		||||
    const headId = clickedConnectionPoint.isHead ? clickedConnectionPoint.areaId : startingContextConnection.areaId
 | 
			
		||||
    const tailId = !clickedConnectionPoint.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
			
		||||
    RequestConnectAreaAsTailToNode(headId, tailId).then(res => console.log(res)).catch(err => console.warn(err))
 | 
			
		||||
    const headId = startingContextConnection.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
			
		||||
    const tailId = !startingContextConnection.isHead ? startingContextConnection.areaId : clickedConnectionPoint.areaId
 | 
			
		||||
    setStartingContextConnection(null)
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await requestConnectProcessedAreas(headId, tailId)
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.warn('RequestConnectProcessedAreas', err)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const renderConnectingPointsForArea = (a: entities.Area) => {
 | 
			
		||||
@ -36,7 +41,7 @@ const ConnectionPoints = (props: Props) => {
 | 
			
		||||
    const headConnector = <Circle
 | 
			
		||||
      key={`head-${a.id}`}
 | 
			
		||||
      id={a.id}
 | 
			
		||||
      radius={10}
 | 
			
		||||
      radius={8}
 | 
			
		||||
      x={((a.startX + a.endX) * scale) / 2}
 | 
			
		||||
      y={a.startY * scale}
 | 
			
		||||
      strokeEnabled={false}
 | 
			
		||||
@ -84,7 +89,7 @@ const ConnectionPoints = (props: Props) => {
 | 
			
		||||
      />)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return <Group>
 | 
			
		||||
    return <Group key={`group-${a.id}`}>
 | 
			
		||||
      {connectorsToRender}
 | 
			
		||||
    </Group>
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -2,18 +2,19 @@
 | 
			
		||||
 | 
			
		||||
import React from 'react'
 | 
			
		||||
import { Line } from 'react-konva'
 | 
			
		||||
import { StartingContextConnection } from '../context/types'
 | 
			
		||||
import { entities } from '../../../wailsjs/wailsjs/go/models'
 | 
			
		||||
import { Coordinates } from '../types'
 | 
			
		||||
import { useStage } from '../context/provider'
 | 
			
		||||
import { useProject } from '../../../context/Project/provider'
 | 
			
		||||
 | 
			
		||||
type CurrentDrawingConnectionProps = {
 | 
			
		||||
  startingContextConnection: StartingContextConnection | null
 | 
			
		||||
  areas: entities.Area[],
 | 
			
		||||
  scale: number,
 | 
			
		||||
  endDrawingPosition: Coordinates | null
 | 
			
		||||
}
 | 
			
		||||
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 <></>
 | 
			
		||||
 | 
			
		||||
  const { areaId, isHead } = startingContextConnection
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,11 @@ import Konva from 'konva'
 | 
			
		||||
import { Coordinates } from '../types'
 | 
			
		||||
import CurrentDrawingConnection from './CurrentDrawingConnection'
 | 
			
		||||
import ConnectionPoints from './ConnectionPoints'
 | 
			
		||||
import ConnectionLines from './ConnectionLines'
 | 
			
		||||
 | 
			
		||||
const ContextConnections = () => {
 | 
			
		||||
  const { getSelectedDocument } = useProject()
 | 
			
		||||
  const { isLinkAreaContextsVisible, startingContextConnection, setStartingContextConnection, scale } = useStage()
 | 
			
		||||
  const { isLinkAreaContextsVisible, startingContextConnection, scale } = useStage()
 | 
			
		||||
  const areas = getSelectedDocument()?.areas || []
 | 
			
		||||
 | 
			
		||||
  const [endDrawingPosition, setEndDrawingPosition] = useState<Coordinates | null>(null)
 | 
			
		||||
@ -34,7 +35,8 @@ const ContextConnections = () => {
 | 
			
		||||
 | 
			
		||||
  return <Group>
 | 
			
		||||
    <ConnectionPoints areas={areas} />
 | 
			
		||||
    <CurrentDrawingConnection areas={areas} startingContextConnection={startingContextConnection} endDrawingPosition={endDrawingPosition} scale={scale} />
 | 
			
		||||
    <ConnectionLines />
 | 
			
		||||
    <CurrentDrawingConnection endDrawingPosition={endDrawingPosition} />
 | 
			
		||||
  </Group>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 { 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 = {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,12 +5,13 @@ const makeDefaultProject = (): ProjectContextType => ({
 | 
			
		||||
  id: '',
 | 
			
		||||
  documents: [] as entities.Document[],
 | 
			
		||||
  groups: [] as entities.Group[],
 | 
			
		||||
  contextGroups: [] as entities.SerializedLinkedProcessedArea[],
 | 
			
		||||
  selectedAreaId: '',
 | 
			
		||||
  selectedDocumentId: '',
 | 
			
		||||
  getSelectedDocument: () => new entities.Document(),
 | 
			
		||||
  getAreaById: (areaId) => undefined,
 | 
			
		||||
  getProcessedAreasByDocumentId: (documentId) => Promise.resolve([new entities.ProcessedArea()]),
 | 
			
		||||
  requestAddProcessedArea: (processesArea) => Promise.resolve(new entities.ProcessedArea()),
 | 
			
		||||
  requestAddProcessedArea: (processesArea) => Promise.resolve(false),
 | 
			
		||||
  requestAddArea: (documentId, area) => Promise.resolve(new entities.Area()),
 | 
			
		||||
  requestUpdateArea: (updatedArea) => Promise.resolve(false),
 | 
			
		||||
  requestDeleteAreaById: (areaId) => Promise.resolve(false),
 | 
			
		||||
@ -33,6 +34,8 @@ const makeDefaultProject = (): ProjectContextType => ({
 | 
			
		||||
  requestUpdateProcessedWordById: (wordId, newTestValue) => Promise.resolve(false),
 | 
			
		||||
  getProcessedAreaById: (areaId) => Promise.resolve(undefined),
 | 
			
		||||
  requestUpdateProcessedArea: updatedProcessedArea => Promise.resolve(false),
 | 
			
		||||
  requestConnectProcessedAreas: (headId, tailId) => Promise.resolve(false),
 | 
			
		||||
  getSerializedContextGroups: () => Promise.resolve([]),
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default makeDefaultProject
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ import createAreaProviderMethods from './createAreaProviderMethods'
 | 
			
		||||
import createDocumentProviderMethods from './createDocumentMethods'
 | 
			
		||||
import createSessionProviderMethods from './createSessionProviderMethods'
 | 
			
		||||
import createUserMarkdownProviderMethods from './createUserMarkdownProviderMethods'
 | 
			
		||||
import createContextGroupProviderMethods from './createContextGroupProviderMethods'
 | 
			
		||||
 | 
			
		||||
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
 | 
			
		||||
 | 
			
		||||
@ -21,15 +22,17 @@ type Props = { children: ReactNode, projectProps: ProjectProps }
 | 
			
		||||
export function ProjectProvider({ children, projectProps }: Props) {
 | 
			
		||||
  const [documents, setDocuments] = useState<entities.Document[]>(projectProps.documents)
 | 
			
		||||
  const [groups, setGroups] = useState<entities.Group[]>(projectProps.groups)
 | 
			
		||||
  const [contextGroups, setContextGroups] = useState<entities.SerializedLinkedProcessedArea[]>(projectProps.contextGroups)
 | 
			
		||||
  const [selectedAreaId, setSelectedAreaId] = useState<string>('')
 | 
			
		||||
  const [selectedDocumentId, setSelectedDocumentId] = useState<string>('')
 | 
			
		||||
  const [currentSession, setCurrentSession] = useState<entities.Session>(new entities.Session())
 | 
			
		||||
 | 
			
		||||
  const updateDocuments = async () => {
 | 
			
		||||
    const response = await GetDocuments()
 | 
			
		||||
    const { documents, groups } = response
 | 
			
		||||
    const { documents, groups, contextGroups } = response
 | 
			
		||||
    setDocuments(documents)
 | 
			
		||||
    setGroups(groups)
 | 
			
		||||
    setContextGroups(contextGroups)
 | 
			
		||||
    return response
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -43,6 +46,7 @@ export function ProjectProvider({ children, projectProps }: Props) {
 | 
			
		||||
  const areaMethods = createAreaProviderMethods({ documents, updateDocuments, selectedDocumentId })
 | 
			
		||||
  const sessionMethods = createSessionProviderMethods({ updateSession, updateDocuments })
 | 
			
		||||
  const userMarkDownMethods = createUserMarkdownProviderMethods()
 | 
			
		||||
  const contextGroupMethods = createContextGroupProviderMethods({ updateDocuments })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
@ -60,6 +64,7 @@ export function ProjectProvider({ children, projectProps }: Props) {
 | 
			
		||||
    id: '',
 | 
			
		||||
    documents,
 | 
			
		||||
    groups,
 | 
			
		||||
    contextGroups,
 | 
			
		||||
    selectedAreaId,
 | 
			
		||||
    setSelectedAreaId,
 | 
			
		||||
    selectedDocumentId,
 | 
			
		||||
@ -69,6 +74,7 @@ export function ProjectProvider({ children, projectProps }: Props) {
 | 
			
		||||
    ...documentMethods,
 | 
			
		||||
    ...sessionMethods,
 | 
			
		||||
    ...userMarkDownMethods,
 | 
			
		||||
    ...contextGroupMethods,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <ProjectContext.Provider value={value}>
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ export type ProjectProps = {
 | 
			
		||||
  id: string,
 | 
			
		||||
  documents: entities.Document[],
 | 
			
		||||
  groups: entities.Group[],
 | 
			
		||||
  contextGroups: entities.SerializedLinkedProcessedArea[],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type AddAreaProps = {
 | 
			
		||||
@ -65,4 +66,6 @@ export type ProjectContextType = {
 | 
			
		||||
  requestUpdateProcessedWordById: (wordId: string, newTextValue: string) => Promise<boolean>
 | 
			
		||||
  getProcessedAreaById: (areaId: string) => Promise<entities.ProcessedArea | undefined>
 | 
			
		||||
  requestUpdateProcessedArea: (updatedProcessedArea: entities.ProcessedArea) => Promise<boolean>
 | 
			
		||||
  requestConnectProcessedAreas: (headId: string, tailId: string) => Promise<boolean>
 | 
			
		||||
  getSerializedContextGroups: () => Promise<entities.SerializedLinkedProcessedArea[]>
 | 
			
		||||
} & ProjectProps
 | 
			
		||||
@ -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 () => {
 | 
			
		||||
  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 {
 | 
			
		||||
  saveDocuments,
 | 
			
		||||
  saveGroups,
 | 
			
		||||
  saveProcessedText,
 | 
			
		||||
  saveUserProcessedMarkdown,
 | 
			
		||||
  saveContextGroups,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								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 GetSerializedContextGroups():Promise<Array<entities.SerializedLinkedProcessedArea>>;
 | 
			
		||||
 | 
			
		||||
export function GetSupportedLanguages():Promise<Array<entities.Language>>;
 | 
			
		||||
 | 
			
		||||
export function GetUserMarkdownByDocumentId(arg1:string):Promise<entities.UserMarkdown>;
 | 
			
		||||
@ -43,7 +45,7 @@ export function RequestChangeSessionProjectByName(arg1:string):Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
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>;
 | 
			
		||||
 | 
			
		||||
@ -51,6 +53,8 @@ export function RequestDeleteDocumentAndChildren(arg1:string):Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
export function RequestDeleteProcessedAreaById(arg1:string):Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
export function RequestSaveContextGroupCollection():Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
export function RequestSaveDocumentCollection():Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
export function RequestSaveGroupCollection():Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,10 @@ export function GetProjectByName(arg1) {
 | 
			
		||||
  return window['go']['ipc']['Channel']['GetProjectByName'](arg1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function GetSerializedContextGroups() {
 | 
			
		||||
  return window['go']['ipc']['Channel']['GetSerializedContextGroups']();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function GetSupportedLanguages() {
 | 
			
		||||
  return window['go']['ipc']['Channel']['GetSupportedLanguages']();
 | 
			
		||||
}
 | 
			
		||||
@ -82,8 +86,8 @@ export function RequestChooseUserAvatar() {
 | 
			
		||||
  return window['go']['ipc']['Channel']['RequestChooseUserAvatar']();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function RequestConnectAreaAsTailToNode(arg1, arg2) {
 | 
			
		||||
  return window['go']['ipc']['Channel']['RequestConnectAreaAsTailToNode'](arg1, arg2);
 | 
			
		||||
export function RequestConnectProcessedAreas(arg1, arg2) {
 | 
			
		||||
  return window['go']['ipc']['Channel']['RequestConnectProcessedAreas'](arg1, arg2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function RequestDeleteAreaById(arg1) {
 | 
			
		||||
@ -98,6 +102,10 @@ export function RequestDeleteProcessedAreaById(arg1) {
 | 
			
		||||
  return window['go']['ipc']['Channel']['RequestDeleteProcessedAreaById'](arg1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function RequestSaveContextGroupCollection() {
 | 
			
		||||
  return window['go']['ipc']['Channel']['RequestSaveContextGroupCollection']();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function 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 {
 | 
			
		||||
	    project: Project;
 | 
			
		||||
	    organization: Organization;
 | 
			
		||||
@ -481,6 +497,7 @@ export namespace ipc {
 | 
			
		||||
	export class GetDocumentsResponse {
 | 
			
		||||
	    documents: entities.Document[];
 | 
			
		||||
	    groups: entities.Group[];
 | 
			
		||||
	    contextGroups: entities.SerializedLinkedProcessedArea[];
 | 
			
		||||
	
 | 
			
		||||
	    static createFrom(source: any = {}) {
 | 
			
		||||
	        return new GetDocumentsResponse(source);
 | 
			
		||||
@ -490,6 +507,7 @@ export namespace ipc {
 | 
			
		||||
	        if ('string' === typeof source) source = JSON.parse(source);
 | 
			
		||||
	        this.documents = this.convertValues(source["documents"], entities.Document);
 | 
			
		||||
	        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 {
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,46 @@
 | 
			
		||||
package ipc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	contextGroup "textualize/core/ContextGroup"
 | 
			
		||||
	document "textualize/core/Document"
 | 
			
		||||
	"textualize/entities"
 | 
			
		||||
	"textualize/storage"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c *Channel) RequestConnectAreaAsTailToNode(tailId string, headId string) bool {
 | 
			
		||||
	processedAreaOfTail := document.GetProcessedAreaCollection().GetAreaById(tailId)
 | 
			
		||||
	if processedAreaOfTail == nil {
 | 
			
		||||
		return false
 | 
			
		||||
func (c *Channel) RequestConnectProcessedAreas(ancestorAreaId string, descendantAreaId string) bool {
 | 
			
		||||
	processedAreaCollection := document.GetProcessedAreaCollection()
 | 
			
		||||
 | 
			
		||||
	ancestorArea := processedAreaCollection.GetAreaById(ancestorAreaId)
 | 
			
		||||
	descendantArea := processedAreaCollection.GetAreaById(descendantAreaId)
 | 
			
		||||
 | 
			
		||||
	wasSuccessfulConnect := contextGroup.GetContextGroupCollection().ConnectProcessedAreas(*ancestorArea, *descendantArea)
 | 
			
		||||
	if wasSuccessfulConnect {
 | 
			
		||||
		wasSuccessfulWrite := c.RequestSaveContextGroupCollection()
 | 
			
		||||
		return wasSuccessfulWrite
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	processedAreaOfHead := document.GetProcessedAreaCollection().GetAreaById(headId)
 | 
			
		||||
	if processedAreaOfHead == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entities.GetContextGroupCollection().ConnectAreaAsTailToNode(*processedAreaOfTail, *processedAreaOfHead)
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,8 +14,9 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GetDocumentsResponse struct {
 | 
			
		||||
	Documents []entities.Document `json:"documents"`
 | 
			
		||||
	Groups    []entities.Group    `json:"groups"`
 | 
			
		||||
	Documents     []entities.Document                      `json:"documents"`
 | 
			
		||||
	Groups        []entities.Group                         `json:"groups"`
 | 
			
		||||
	ContextGroups []entities.SerializedLinkedProcessedArea `json:"contextGroups"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	documents := document.GetDocumentCollection().Documents
 | 
			
		||||
	groups := document.GetGroupCollection().Groups
 | 
			
		||||
	contextGroups := c.GetSerializedContextGroups()
 | 
			
		||||
 | 
			
		||||
	response := GetDocumentsResponse{
 | 
			
		||||
		Groups:    make([]entities.Group, 0),
 | 
			
		||||
		Documents: make([]entities.Document, 0),
 | 
			
		||||
		Groups:        make([]entities.Group, 0),
 | 
			
		||||
		Documents:     make([]entities.Document, 0),
 | 
			
		||||
		ContextGroups: contextGroups,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, d := range documents {
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package ipc
 | 
			
		||||
import (
 | 
			
		||||
	app "textualize/core/App"
 | 
			
		||||
	consts "textualize/core/Consts"
 | 
			
		||||
	contextGroup "textualize/core/ContextGroup"
 | 
			
		||||
	document "textualize/core/Document"
 | 
			
		||||
	session "textualize/core/Session"
 | 
			
		||||
	"textualize/entities"
 | 
			
		||||
@ -144,6 +145,7 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
			
		||||
 | 
			
		||||
	session.GetInstance().Project = foundProject
 | 
			
		||||
 | 
			
		||||
	// Documents
 | 
			
		||||
	localDocumentCollection := storageDriver.ReadDocumentCollection(projectName)
 | 
			
		||||
	documentCount := len(localDocumentCollection.Documents)
 | 
			
		||||
	readableDocuments := make([]document.Entity, documentCount)
 | 
			
		||||
@ -155,6 +157,7 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
			
		||||
		ProjectId: foundProject.Id,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Groups
 | 
			
		||||
	localGroupsCollection := storageDriver.ReadGroupCollection(projectName)
 | 
			
		||||
	groupCount := len(localGroupsCollection.Groups)
 | 
			
		||||
	readableGroups := make([]entities.Group, groupCount)
 | 
			
		||||
@ -167,6 +170,10 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool {
 | 
			
		||||
		Groups:    readableGroups,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Context Groups
 | 
			
		||||
	localSerializedContextGroups := storageDriver.ReadContextGroupCollection(projectName)
 | 
			
		||||
	contextGroup.SetContextGroupCollectionBySerialized(localSerializedContextGroups)
 | 
			
		||||
 | 
			
		||||
	// Processed Texts
 | 
			
		||||
	localProcessedAreaCollection := storageDriver.ReadProcessedTextCollection(projectName)
 | 
			
		||||
	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
 | 
			
		||||
	WriteProcessedUserMarkdownCollection(entities.ProcessedUserMarkdownCollection, string) bool
 | 
			
		||||
	ReadProcessedUserMarkdownCollection(string) entities.ProcessedUserMarkdownCollection
 | 
			
		||||
	WriteContextGroupCollection([]entities.SerializedLinkedProcessedArea, string) bool
 | 
			
		||||
	ReadContextGroupCollection(string) []entities.SerializedLinkedProcessedArea
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var driverInstance Driver
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user