@@ -26,7 +26,6 @@ import org.silkframework.runtime.activity.{Activity, UserContext}
2626import org .silkframework .runtime .plugin .PluginContext
2727import org .silkframework .runtime .resource .ResourceManager
2828import org .silkframework .runtime .serialization .{ReadContext , WriteContext }
29- import org .silkframework .runtime .templating .{GlobalTemplateVariables , TemplateVariablesReader }
3029import org .silkframework .runtime .validation .{BadUserInputException , NotFoundException , ValidationError , ValidationException }
3130import org .silkframework .serialization .json .JsonParseException
3231import org .silkframework .serialization .json .JsonSerializers ._
@@ -276,22 +275,46 @@ class TransformTaskApi @Inject() () extends InjectedController with UserContextA
276275 implicit val (project, task) = getProjectAndTask[TransformSpec ](projectName, taskName)
277276 implicit val prefixes : Prefixes = project.config.prefixes
278277 validateJson[RuleAutoCompletionRequest ] { requestData =>
279- val allRules = task.data.allRulesRecursive
278+ val searchQuery = requestData.searchQuery.getOrElse(" " )
279+ val format = requestData.format.getOrElse(false )
280+ val maxResults = requestData.limit.getOrElse(Int .MaxValue )
280281 val filter : TransformRule => Boolean = (requestData.objectRulesOnly.getOrElse(false ), requestData.valueRulesOnly.getOrElse(false )) match {
281282 case (true , false ) => (r : TransformRule ) => r.isInstanceOf [ContainerTransformRule ]
282283 case (false , true ) => (r : TransformRule ) => r.isInstanceOf [ValueTransformRule ]
283284 case _ => (_ : TransformRule ) => true
284285 }
285- val completions : Seq [Completion ] = allRules
286- .filter(filter)
287- .map(r => Completion (
288- value = r.id,
289- label = Some (r.fullLabel),
290- description = r.metaData.description,
291- category = Categories .rules,
292- isCompletion = true
293- ))
294- Ok (Completions (completions).filterAndSort(requestData.searchQuery.getOrElse(" " ), requestData.limit.getOrElse(Int .MaxValue ), multiWordFilter = true ).toJson)
286+ if (searchQuery.trim.isEmpty) {
287+ val formattedLabels = format && ! requestData.valueRulesOnly.getOrElse(false )
288+ val formattedLabelsByRule = if (formattedLabels) {
289+ TransformTaskApi .formattedRulesInTreeOrder(task.data.mappingRule, filter).toMap
290+ } else {
291+ Map .empty[TransformRule , String ]
292+ }
293+ val completions = TransformTaskApi .rulesInTreeOrder(task.data.mappingRule)
294+ .filter(filter)
295+ .map { rule =>
296+ Completion (
297+ value = rule.id,
298+ label = Some (formattedLabelsByRule.getOrElse(rule, rule.fullLabel)),
299+ description = rule.metaData.description,
300+ category = Categories .rules,
301+ isCompletion = true
302+ )
303+ }
304+ .take(maxResults)
305+ Ok (Completions (completions).toJson)
306+ } else {
307+ val completions : Seq [Completion ] = task.data.allRulesRecursive
308+ .filter(filter)
309+ .map(r => Completion (
310+ value = r.id,
311+ label = Some (r.fullLabel),
312+ description = r.metaData.description,
313+ category = Categories .rules,
314+ isCompletion = true
315+ ))
316+ Ok (Completions (completions).filterAndSort(searchQuery, maxResults, multiWordFilter = true ).toJson)
317+ }
295318 }
296319 }
297320
@@ -1055,5 +1078,43 @@ object TransformTaskApi {
10551078
10561079 // The property that is set when copying a root mapping rule that will be converted into an object mapping rule
10571080 final val ROOT_COPY_TARGET_PROPERTY = " urn:temp:child"
1058- }
10591081
1082+ private def rulesInTreeOrder (rule : TransformRule ): Seq [TransformRule ] = {
1083+ rule +: rule.rules.allRules.flatMap(rulesInTreeOrder)
1084+ }
1085+
1086+ private def formattedRulesInTreeOrder (rule : TransformRule , filter : TransformRule => Boolean )
1087+ (implicit prefixes : Prefixes ): Seq [(TransformRule , String )] = {
1088+ def hasVisibleNodes (currentRule : TransformRule ): Boolean = {
1089+ filter(currentRule) || currentRule.rules.allRules.exists(hasVisibleNodes)
1090+ }
1091+
1092+ def visibleChildren (currentRule : TransformRule ): Seq [TransformRule ] = {
1093+ currentRule.rules.allRules.filter(hasVisibleNodes)
1094+ }
1095+
1096+ def render (currentRule : TransformRule ,
1097+ ancestorLastStates : Seq [Boolean ],
1098+ isLast : Boolean ,
1099+ isRoot : Boolean ): Seq [(TransformRule , String )] = {
1100+ val currentPrefix =
1101+ if (isRoot) {
1102+ " "
1103+ } else {
1104+ ancestorLastStates.map(last => if (last) " " else " │ " ).mkString + (if (isLast) " └─ " else " ├─ " )
1105+ }
1106+ val currentEntry = if (filter(currentRule)) {
1107+ Seq (currentRule -> (currentPrefix + currentRule.fullLabel))
1108+ } else {
1109+ Seq .empty
1110+ }
1111+ val nextAncestorLastStates = if (isRoot) ancestorLastStates else ancestorLastStates :+ isLast
1112+ val children = visibleChildren(currentRule)
1113+ currentEntry ++ children.zipWithIndex.flatMap { case (child, index) =>
1114+ render(child, nextAncestorLastStates, isLast = index == children.size - 1 , isRoot = false )
1115+ }
1116+ }
1117+
1118+ render(rule, Seq .empty, isLast = true , isRoot = true )
1119+ }
1120+ }
0 commit comments