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