Skip to content

Commit f7a9e28

Browse files
committed
copy author edges with their times but executing user in automation
1 parent e0b930a commit f7a9e28

File tree

6 files changed

+23
-15
lines changed

6 files changed

+23
-15
lines changed

graph/src/main/scala/GraphChanges.scala

+6-3
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ case class GraphChanges(
1111
// we do not really need a connection for deleting (ConnectionId instead), but we want to revert it again.
1212
delEdges: collection.Set[Edge] = Set.empty
1313
) {
14-
def withAuthor(userId: UserId, timestamp: EpochMilli = EpochMilli.now): GraphChanges =
14+
def withAuthor(userId: UserId, timestamp: EpochMilli = EpochMilli.now): GraphChanges = {
15+
val existingAuthors: Set[NodeId] = addEdges.collect { case edge: Edge.Author => edge.nodeId }(breakOut)
1516
copy(
16-
addEdges = addEdges ++
17-
addNodes.map(node => Edge.Author(node.id, EdgeData.Author(timestamp), userId))
17+
addEdges = addEdges ++ addNodes.flatMap { node =>
18+
(if (existingAuthors(node.id)) Set.empty[Edge] else Set[Edge](Edge.Author(node.id, EdgeData.Author(timestamp), userId)))
19+
}
1820
)
21+
}
1922

2023
def merge(other: GraphChanges): GraphChanges = {
2124
GraphChanges.from(

sdk/shared/src/main/scala/EventProcessor.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import monix.reactive.{Observable, OverflowStrategy}
55
import monix.reactive.subjects.{PublishSubject, PublishToOneSubject}
66
import wust.api.ApiEvent._
77
import wust.api._
8-
import wust.ids.NodeId
8+
import wust.ids.{NodeId, UserId}
99
import wust.graph._
1010

1111
import scala.concurrent.Future
@@ -36,7 +36,7 @@ object EventProcessor {
3636
//TODO factory and constructor shared responsibility
3737
def apply(
3838
eventStream: Observable[Seq[ApiEvent]],
39-
enrichChanges: (GraphChanges, Graph) => GraphChanges,
39+
enrichChanges: (GraphChanges, UserId, Graph) => GraphChanges,
4040
sendChange: List[GraphChanges] => Future[Boolean],
4141
initialAuth: Authentication
4242
)(implicit scheduler: Scheduler): EventProcessor = {
@@ -62,7 +62,7 @@ object EventProcessor {
6262
class EventProcessor private (
6363
eventStream: Observable[Seq[ApiEvent.GraphContent]],
6464
authEventStream: Observable[Seq[ApiEvent.AuthContent]],
65-
enrichChanges: (GraphChanges, Graph) => GraphChanges,
65+
enrichChanges: (GraphChanges, UserId, Graph) => GraphChanges,
6666
sendChange: List[GraphChanges] => Future[Boolean],
6767
val initialAuth: Authentication
6868
)(implicit scheduler: Scheduler) {
@@ -92,8 +92,8 @@ class EventProcessor private (
9292
val sharedRawGraph = rawGraph.share
9393
val rawGraphWithInit = sharedRawGraph.startWith(Seq(Graph.empty))
9494

95-
val enrichedChanges = changes.withLatestFrom(rawGraphWithInit) { (changes, graph) =>
96-
val newChanges = enrichChanges(changes, graph)
95+
val enrichedChanges = changes.withLatestFrom2(currentUser, rawGraphWithInit) { (changes, user, graph) =>
96+
val newChanges = enrichChanges(changes, user.id, graph)
9797
scribe.info(s"Local Graphchanges: ${newChanges.toPrettyString(graph)}")
9898
newChanges
9999
}

webApp/src/main/scala/state/GlobalStateFactory.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object GlobalStateFactory {
3737

3838
val eventProcessor = EventProcessor(
3939
Client.observable.event,
40-
(changes, graph) => GraphChangesAutomation.enrich(graph, urlConfig, EmojiReplacer.replaceChangesToColons(changes)).consistent,
40+
(changes, userId, graph) => GraphChangesAutomation.enrich(userId, graph, urlConfig, EmojiReplacer.replaceChangesToColons(changes)).consistent,
4141
Client.api.changeGraph,
4242
Client.currentAuth
4343
)

webApp/src/main/scala/state/GraphChangesAutomation.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object GraphChangesAutomation {
2323

2424
// copy the whole subgraph of the templateNode and append it to newNode.
2525
// templateNode is a placeholder and we want make changes such newNode looks like a copy of templateNode.
26-
def copySubGraphOfNode(graph: Graph, newNode: Node, templateNode: Node, newId: NodeId => NodeId = _ => NodeId.fresh, copyTime: EpochMilli = EpochMilli.now): GraphChanges = {
26+
def copySubGraphOfNode(userId: UserId, graph: Graph, newNode: Node, templateNode: Node, newId: NodeId => NodeId = _ => NodeId.fresh, copyTime: EpochMilli = EpochMilli.now): GraphChanges = {
2727
scribe.info(s"Copying sub graph of node $newNode with template $templateNode")
2828

2929
val templateNodeIdx = graph.idToIdxOrThrow(templateNode.id)
@@ -100,10 +100,15 @@ object GraphChangesAutomation {
100100
// Go through all edges and create new edges pointing to the replacedNodes, so
101101
// that we copy the edge structure that the template node had.
102102
graph.edges.foreach {
103-
case _: Edge.Author => () // do not copy authors, we want the new authors of the one who triggered this change.
104103
case _: Edge.DerivedFromTemplate => () // do not copy derived info, we get new derive infos for new nodes
105104
case edge: Edge.Automated if edge.templateNodeId == templateNode.id => () // do not copy automation edges of template, otherwise the newNode would become a template.
106105
case edge: Edge.Child if edge.data.deletedAt.exists(EpochMilli.now.isAfter) => () // do not copy deleted parent edges
106+
case edge: Edge.Author => // need to keep date of authorship, but change author. We will have an author edge for every change that was done to this node
107+
// replace node ids to point to our copied nodes
108+
replacedNodes.get(edge.nodeId) match {
109+
case Some(newSource) => addEdges += edge.copy(nodeId = newSource.id, userId = userId)
110+
case None => ()
111+
}
107112
case edge =>
108113
// replace node ids to point to our copied nodes
109114
(replacedNodes.get(edge.sourceId), replacedNodes.get(edge.targetId)) match {
@@ -121,7 +126,7 @@ object GraphChangesAutomation {
121126
// We get the current graph + the new graph change. For each new parent edge in the graph change,
122127
// we check if the parent has a template node. If the parent has a template node, we want to
123128
// append the subgraph (which is spanned from the template node) to the newly inserted child of the parent.
124-
def enrich(graph: Graph, viewConfig: Var[UrlConfig], changes: GraphChanges): GraphChanges = {
129+
def enrich(userId: UserId, graph: Graph, viewConfig: Var[UrlConfig], changes: GraphChanges): GraphChanges = {
125130
scribe.info("Check for automation enrichment of graphchanges: " + changes.toPrettyString(graph))
126131

127132
val addNodes = mutable.HashSet.newBuilder[Node]
@@ -153,7 +158,7 @@ object GraphChangesAutomation {
153158
val templateNode = graph.nodes(templateNodeIdx)
154159
if (templateNode.role == childNode.role) {
155160
scribe.info(s"Found fitting template '$templateNode' for '$childNode'")
156-
val changes = copySubGraphOfNode(graph, newNode = childNode, templateNode = templateNode)
161+
val changes = copySubGraphOfNode(userId, graph, newNode = childNode, templateNode = templateNode)
157162
// if the automated changes re-add the same child edge were are currently replacing, then we want to take the ordering from the new child edge.
158163
// so an automated node can be drag/dropped to the correct position.
159164
addEdges ++= changes.addEdges.map {

webApp/src/main/scala/views/TableView.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ object TableView {
190190
// now we add these changes with the template node to a temporary graph, because ChangesAutomation needs the template node in the graph
191191
val tmpGraph = state.rawGraph.now applyChanges changes
192192
// run automation of this template for each row
193-
propertyGroup.infos.foldLeft[GraphChanges](changes)((changes, info) => changes merge GraphChangesAutomation.copySubGraphOfNode(tmpGraph, info.node, templateNode = templateNode))
193+
propertyGroup.infos.foldLeft[GraphChanges](changes)((changes, info) => changes merge GraphChangesAutomation.copySubGraphOfNode(state.user.now.id, tmpGraph, info.node, templateNode = templateNode))
194194
} else propertyGroup.infos.foldLeft[GraphChanges](GraphChanges.empty)((changes, info) => changes merge changesf(info.node.id))
195195
}, keepPropertyAsDefault),
196196
dropdownModifier = cls := "top right",

webApp/src/test/scala/GraphChangesAutomationSpec.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class GraphChangesAutomationSpec extends FreeSpec with MustMatchers {
2222
val copyTime = EpochMilli.now
2323

2424
def copySubGraphOfNode(graph: Graph, newNode: Node, templateNode: Node) = GraphChangesAutomation.copySubGraphOfNode(
25-
graph, newNode, templateNode, copyNodeId(_), copyTime
25+
freshNodeId(), graph, newNode, templateNode, copyNodeId(_), copyTime
2626
)
2727

2828
"empty template node" in {

0 commit comments

Comments
 (0)