@@ -107,6 +107,7 @@ object Components {
107107 // 4. crop via overflow ellipsis
108108 cls := " oneline"
109109 )
110+
110111 }
111112
112113 def nodeCardAsOneLineText (node : Node , projectWithIcon : Boolean = true )(implicit ctx : Ctx .Owner ): VNode = {
@@ -650,7 +651,7 @@ object Components {
650651 def searchAndSelectNodeApplied [F [_] : Sink : Source ](current : F [Option [NodeId ]], filter : Node => Boolean )(implicit ctx : Ctx .Owner ): VNode = searchAndSelectNode(current, filter) --> current
651652 def searchAndSelectNode [F [_] : Source ](observable : F [Option [NodeId ]], filter : Node => Boolean )(implicit ctx : Ctx .Owner ): EmitterBuilder [Option [NodeId ], VNode ] =
652653 Components .searchInGraph(GlobalState .rawGraph, " Search" , filter = {
653- case n : Node .Content => InlineList .contains[ NodeRole ]( NodeRole . Message , NodeRole . Task , NodeRole . Project )(n.role) && filter(n)
654+ case n : Node .Content => filter(n)
654655 case _ => false
655656 }, innerElementModifier = width := " 100%" , inputModifiers = width := " 100%" ).mapResult[VNode ] { search =>
656657 div(
@@ -687,18 +688,47 @@ object Components {
687688 minCharacters = 0
688689 showNoResults = showNotFound
689690
690- source = graph.now.nodes.collect { case node : Node if filter(node) =>
691- val str = node match {
692- case user : Node .User => Components .displayUserName(user.data)
693- case _ => node.str
694- }
691+ source = {
692+ val g : Graph = graph.now
693+ val res1 = (g.nodes.collect { case node : Node if filter(node) && node.role == NodeRole .Neutral =>
695694
696- new SearchSourceEntry {
697- title = node.id.toCuidString
698- description = trimToMaxLength(str, 36 )
699- data = node.asInstanceOf [js.Any ]
700- }
701- }(breakOut): js.Array [SearchSourceEntry ]
695+ val probEdgesRev = g.propertiesEdgeReverseIdx(g.idToIdxOrThrow(node.id))
696+
697+ val probData = probEdgesRev.map{ idx =>
698+ val keyString = g.edges(idx).as[Edge .LabeledProperty ].data.key
699+ val propertyValue = g.nodes(g.edgesIdx.b(idx))
700+ val propertySource = g.nodes(g.edgesIdx.a(idx))
701+ (keyString, propertyValue, propertySource)
702+ }
703+
704+ probData.collect {
705+ case p : (String , Node , Node ) if p._2.data.isInstanceOf [NodeData .Placeholder ] =>
706+ new SearchSourceEntry {
707+ title = p._2.id.toCuidString
708+ placeholder = true
709+ text = s " ${p._1} of ${p._3.str}"
710+ description = trimToMaxLength(s " missing ${p._1} of ${p._3.str}" , 36 )
711+ data = node.asInstanceOf [js.Any ]
712+ }
713+ }(breakOut): js.Array [SearchSourceEntry ]
714+ }(breakOut): js.Array [js.Array [SearchSourceEntry ]]).flatten
715+
716+ val res2 = g.nodes.collect { case node : Node if filter(node) && node.role != NodeRole .Neutral =>
717+ val str = node match {
718+ case user : Node .User => Components .displayUserName(user.data)
719+ case n : Node .Content => node.str
720+ }
721+
722+ new SearchSourceEntry {
723+ title = node.id.toCuidString
724+ placeholder = false
725+ description = trimToMaxLength(str, 36 )
726+ data = node.asInstanceOf [js.Any ]
727+ }
728+ }(breakOut): js.Array [SearchSourceEntry ]
729+
730+ res2 ++ res1
731+ }
702732
703733 searchFields = js.Array (" description" )
704734
0 commit comments