diff --git a/libs/gui-elements b/libs/gui-elements index 47cdaefc57..e61fa1b7d1 160000 --- a/libs/gui-elements +++ b/libs/gui-elements @@ -1 +1 @@ -Subproject commit 47cdaefc57ccd76705366d7831227e6fe03c8302 +Subproject commit e61fa1b7d19f09172473c9adb3c9afb3745b4476 diff --git a/package.json b/package.json index 763e9dcd4f..c8ece31b40 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ ], "scripts": {}, "dependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "devDependencies": {}, "resolutions": { @@ -22,10 +22,11 @@ "**/minimist": "1.2.8", "**/moment": "2.29.4", "**/nanoid": "3.3.4", - "**/react": "^17.0.2", - "**/react-dom": "^17.0.2", + "**/react": "^18.2.0", + "**/react-dom": "^18.2.0", "**/semver-regex": "3.1.4", - "**/@types/react": "^17.0.85", - "**/url-parse": "1.5.9" + "**/@types/react": "^18.2.0", + "**/url-parse": "1.5.9", + "**/react-redux": "^9.1.2" } } diff --git a/silk-workbench/silk-workbench-core/app/controllers/core/Branding.scala b/silk-workbench/silk-workbench-core/app/controllers/core/Branding.scala index e65af3c642..680348cd24 100644 --- a/silk-workbench/silk-workbench-core/app/controllers/core/Branding.scala +++ b/silk-workbench/silk-workbench-core/app/controllers/core/Branding.scala @@ -18,11 +18,6 @@ class Branding @Inject() () extends InjectedController { Ok(bytes).as("image/png").withHeaders("Cache-Control" -> "public, max-age=86400") } - def aboutDialog = Action { - val aboutHtml = Html(WorkbenchConfig.get.about.loadAsString()) - Ok(views.html.aboutDialog(aboutHtml)) - } - def mdlStyle = Action { val bytes = WorkbenchConfig.get.mdlStyle.get.loadAsBytes Ok(bytes).as("text/css") diff --git a/silk-workbench/silk-workbench-core/app/controllers/core/Start.scala b/silk-workbench/silk-workbench-core/app/controllers/core/Start.scala deleted file mode 100644 index 5399152a66..0000000000 --- a/silk-workbench/silk-workbench-core/app/controllers/core/Start.scala +++ /dev/null @@ -1,30 +0,0 @@ -package controllers.core - -import config.WorkbenchConfig -import config.WorkbenchConfig.WorkspaceReact -import play.api.mvc.{Action, AnyContent, InjectedController} -import play.twirl.api.Html - -import javax.inject.Inject - -class Start @Inject() (implicit workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def index: Action[AnyContent] = RequestUserContextAction { implicit request =>implicit userContext => - val welcome = Html(WorkbenchConfig.get.welcome.loadAsString()) - Ok(views.html.start(welcome)) - } -} - -object Start { - - def deployPath: String = { - val loggedOutFull = controllers.core.routes.Start.index.url.toString - val path = loggedOutFull.dropRight("core/start".length) - if(path.isEmpty) { - "/" - } else { - path - } - } - -} diff --git a/silk-workbench/silk-workbench-core/app/views/aboutDialog.scala.html b/silk-workbench/silk-workbench-core/app/views/aboutDialog.scala.html deleted file mode 100644 index ff6b044bd3..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/aboutDialog.scala.html +++ /dev/null @@ -1,22 +0,0 @@ -@import config.WorkbenchConfig - -@(content: Html) - -@widgets.dialog(title = "About", width = 500) { -
-
- -

@WorkbenchConfig.get.title, @WorkbenchConfig.version

- @content -
-
- -} diff --git a/silk-workbench/silk-workbench-core/app/views/clientError.scala.html b/silk-workbench/silk-workbench-core/app/views/clientError.scala.html index e33017e4f5..a3f4e2c679 100644 --- a/silk-workbench/silk-workbench-core/app/views/clientError.scala.html +++ b/silk-workbench/silk-workbench-core/app/views/clientError.scala.html @@ -2,18 +2,23 @@ @(errorMessage: String)(implicit request: RequestHeader, workspaceReact: WorkspaceReact) @content = { -
-
-
-
+
+
+
+

Error

-
-
-
-

@errorMessage

+
+
+
+
+
diff --git a/silk-workbench/silk-workbench-core/app/views/configView.scala.html b/silk-workbench/silk-workbench-core/app/views/configView.scala.html index a55e1bf0a8..7e4f6f9780 100644 --- a/silk-workbench/silk-workbench-core/app/views/configView.scala.html +++ b/silk-workbench/silk-workbench-core/app/views/configView.scala.html @@ -36,13 +36,31 @@ } @content = { -
- - -
- -
- @render(config.root()) +
+
+
+
+

+ Configuration +

+
+
+
+
+
+ + + + + + +
+
+
+ @render(config.root()) +
+
+
} diff --git a/silk-workbench/silk-workbench-core/app/views/frame.scala.html b/silk-workbench/silk-workbench-core/app/views/frame.scala.html index 33191f7e5a..1992d715ca 100644 --- a/silk-workbench/silk-workbench-core/app/views/frame.scala.html +++ b/silk-workbench/silk-workbench-core/app/views/frame.scala.html @@ -10,14 +10,10 @@ @config.workbench.title - - - - @@ -28,27 +24,10 @@ publicBaseUrl:"@{WorkbenchConfig.publicBaseUrl}" } - @header - @coreLinks.mainStyles() - - @if(config.workbench.mdlStyle.isDefined) { - @* This indicates that Silk is running in a modified version which can supply an alternative version of MDL. *@ - - } - - - - - - - - - - @content diff --git a/silk-workbench/silk-workbench-core/app/views/main.scala.html b/silk-workbench/silk-workbench-core/app/views/main.scala.html index c69a3f27f2..8479f7ec87 100644 --- a/silk-workbench/silk-workbench-core/app/views/main.scala.html +++ b/silk-workbench/silk-workbench-core/app/views/main.scala.html @@ -1,39 +1,12 @@ -@import config.WorkbenchConfig -@import controllers.core.Start +@import config.WorkbenchConfig.WorkspaceReact @import org.silkframework.config.TaskSpec @import org.silkframework.workbench.Context - -@import config.WorkbenchConfig.WorkspaceReact @(context: Option[Context[_ <: TaskSpec]], selectedTab: String = "", titleLabel: String = "")(header: Html)(toolbar: Html)(content: Html)(implicit request: RequestHeader, workspaceReact: WorkspaceReact) @frame(header) { - - @* Filled with template dialog.scala.html *@ - - - @* Filled with template dialog.scala.html *@ - - -
-
- - @if(config.workbench.showHeader(request)) { - @tabbar(context, selectedTab, titleLabel) - } - @if(toolbar != null) { -
- @toolbar -
- } -
-
- @content -
-
-
-
-
+
+
+ @content
-
} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-core/app/views/serverError.scala.html b/silk-workbench/silk-workbench-core/app/views/serverError.scala.html index 6721c87a6e..ab7ed2976a 100644 --- a/silk-workbench/silk-workbench-core/app/views/serverError.scala.html +++ b/silk-workbench/silk-workbench-core/app/views/serverError.scala.html @@ -11,70 +11,71 @@ @frame { } { -
-
-
-
-

- @{title.getOrElse(exception.title)} -

-
-
-
-
-

@{details.getOrElse(exception.description)}

-
+
+
+
+
+

+ @{title.getOrElse(exception.title)} +

- @if(showExceptionId) { -
- This exception has been logged with id @exception.id. +
+
+
+
+ - } +
@if(showDetails) { -
- - -
- } -
- @if(showDetails) { -
-
-
- - } @stacktrace(ex: Throwable) = { -

+ @for(el <- ex.getStackTrace) { @el.toString -
} -

+ @if(ex.getCause != null) { Cause: @ex.getCause.getMessage diff --git a/silk-workbench/silk-workbench-core/app/views/start.scala.html b/silk-workbench/silk-workbench-core/app/views/start.scala.html deleted file mode 100644 index ffbf9f0195..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/start.scala.html +++ /dev/null @@ -1,64 +0,0 @@ -@import config.WorkbenchConfig.WorkspaceReact -@import org.silkframework.runtime.activity.UserContext -@import controllers.core.routes.Branding -@(welcome: Html)(implicit request: RequestHeader, userContext: UserContext, workspaceReact: WorkspaceReact) - -@exampleName = @{ "movies" } - -@projects = @{ org.silkframework.workspace.WorkspaceFactory().workspace.userProjects } - -@header = { - @coreLinks.mainStyles() -} - -@content = { -
-
-
-
- - @welcome -
- -

- Your current workspace contains @projects.size project(s). -

-
-
-
-
- - - Open workspace - -
- Switch to workspace UI -
-
-   - - - @if(!projects.exists(_.id == exampleName)) { - -   - } -
-
- -} - -@main(None, "start")(header)(null)(content) diff --git a/silk-workbench/silk-workbench-core/app/views/tabbar.scala.html b/silk-workbench/silk-workbench-core/app/views/tabbar.scala.html deleted file mode 100644 index 1ef02a0efc..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/tabbar.scala.html +++ /dev/null @@ -1,76 +0,0 @@ -@import org.silkframework.workbench.WorkbenchPlugins -@import org.silkframework.config.{ProductionConfig, TaskSpec} -@import org.silkframework.workbench.Context -@import config.WorkbenchConfig - -@(context: Option[Context[_ <: TaskSpec]], selectedTab: String, titleLabel: String)(implicit request: RequestHeader) - -@pluginTabs = { - @for(cont <- context.toSeq; - plugin = WorkbenchPlugins.forTask(cont.task); - tab <- plugin.tabs) { - @tab.title - } -} - -@safeModeButton = { - - @if(ProductionConfig.safeModeEnabled) { -
- -
-
- Safe-mode prevents access to external data systems, e.g. JDBC, SPARQL datasets. Data access in executed workflows is not affected by the safe-mode. -
- } -} - -
-
- @titleLabel - Start - Workspace - Activities - @pluginTabs - @safeModeButton - - -
    -
  • About
  • -
  • Configuration
  • - @if(WorkbenchConfig.get.showLogoutButton && request.session.get("loggedIn").contains("true")) { -
  • Logout
  • - } -
- -
-
\ No newline at end of file diff --git a/silk-workbench/silk-workbench-core/app/views/widgets/dialog.scala.html b/silk-workbench/silk-workbench-core/app/views/widgets/dialog.scala.html deleted file mode 100644 index 1a19b4a842..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/widgets/dialog.scala.html +++ /dev/null @@ -1,66 +0,0 @@ - -@(title: String, - width: Int = 700, - submitLabel: String = "OK", - secondaryLabel: String = "Secondary Button", - createDialog: Boolean = true)(content: Html) - -
-
-
-

@title

-
-
-
-
-
- Error message. -
-
-
-
-
- @content -
-
- - - @if(createDialog) { - - } else { - - } -
-
- -
diff --git a/silk-workbench/silk-workbench-core/app/views/widgets/multilineParameter.scala.html b/silk-workbench/silk-workbench-core/app/views/widgets/multilineParameter.scala.html deleted file mode 100644 index 8da3f2eb3a..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/widgets/multilineParameter.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@(mainId: String, value: String, label: String, tooltip: String, additionalInputElementsClass: String = "") - -
- - -
- @tooltip -
-
- - diff --git a/silk-workbench/silk-workbench-core/app/views/widgets/pluginDialog.scala.html b/silk-workbench/silk-workbench-core/app/views/widgets/pluginDialog.scala.html deleted file mode 100644 index c66d965bf2..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/widgets/pluginDialog.scala.html +++ /dev/null @@ -1,296 +0,0 @@ -@import org.silkframework.dataset.DatasetPluginAutoConfigurable -@import org.silkframework.runtime.plugin.StringParameterType._ -@import org.silkframework.runtime.plugin.{AnyPlugin, PluginParameter, StringParameterType, PluginDescription} -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.runtime.plugin.PluginCategories - -@import org.silkframework.runtime.plugin.PluginContext -@(project: Project, - name: String, - plugins: Seq[PluginDescription[_]], - currentObj: Option[AnyPlugin], - resources: List[String], - title: String = "Edit Properties", - submitLabel: String = "OK", - secondaryLabel: String = "Secondary", - createDialog: Boolean = false)(contents: Html)(implicit userContext: UserContext) - -@dialog(title = title, submitLabel = submitLabel, secondaryLabel = secondaryLabel, width = 500, createDialog = createDialog) { -
-
- - -
- - @for(plugin <- plugins) { - @createTab(plugin) - } -
- - @contents -} - -@sortPlugins(plugins: Seq[PluginDescription[_]]) = @{ - plugins.filterNot(_.categories.contains(PluginCategories.deprecated)) - .sortBy(_.label) - .sortBy(_.categories.headOption.getOrElse("").toLowerCase) -} - -@pluginLabel(plugin: PluginDescription[_]) = { - @if(plugin.categories == Seq(PluginCategories.uncategorized)) { - @plugin.label - } else { - @plugin.label (@plugin.categories.mkString(", ")) - } -} - -@createTab(plugin: PluginDescription[_]) = { -
-

- @plugin.description -

- - @if(createDialog) { -
- - -
- } - - @for(param <- plugin.parameters) { - @if(param.visibleInDialog) { - @createField(plugin.id, param) - } - } - -
- - -} - -@** - * Creates a new field for a plugin parameter - *@ -@createField(pluginId: String, param: PluginParameter) = @{ - param.parameterType match { - case StringParameterType.ResourceType | StringParameterType.WritableResourceType => createResourceField(pluginId, param) - case enum @ StringParameterType.EnumerationType(_) => createEnumerationField(pluginId, param, enum.enumerationValues, enum.displayNames) - case BooleanType => createEnumerationField(pluginId, param, Seq("true", "false"), Seq("True", "False")) - case MultilineStringParameterType => createMultilineTextField(pluginId, param) - case SparqlEndpointDatasetParameterType => createSparqlEndpointDatasetField(pluginId, param) - case PasswordParameterType => createTextField(pluginId, param, inputType = "password") - case _ => createTextField(pluginId, param) - } -} - -@createTextField(pluginId: String, param: PluginParameter, inputType: String = "text") = { -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - -@createMultilineTextField(pluginId: String, param: PluginParameter) = { - @widgets.multilineParameter(s"${pluginId}_${param.name}", value(pluginId, param), label = param.label, tooltip = param.description, additionalInputElementsClass = "plugin-dialog-multi-line-textfield") -} - -@createSparqlEndpointDatasetField(pluginId: String, param: PluginParameter)(implicit userContext: UserContext) = { - @widgets.sparqlDatasetSelect(project.id, param.label, param.description, pluginId + "_" + param.name, if(value(pluginId, param) == "") None else Some(value(pluginId, param))) -} - -@createEnumerationField(pluginId: String, param: PluginParameter, enumerationValues: Seq[String], displayNames: Seq[String]) = { -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - -@createResourceField(pluginId: String, param: PluginParameter) = { -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - -@** - * Retrieves the value of a specific parameter - *@ -@value(pluginId: String, param: PluginParameter) = @{ - // Retrieve parameter value as Object - val paramObj = - currentObj match { - case Some(obj) if obj.pluginSpec.id.toString == pluginId => - Option(param(obj)) - case _ => - param.defaultValue.flatMap(Option(_)) - } - // Convert parameter value to string - implicit val prefixes = project.config.prefixes - val paramType = param.parameterType.asInstanceOf[StringParameterType[AnyRef]] - val paramStr = paramObj.map(pv => paramType.toString(pv)(PluginContext.empty)).getOrElse("") - paramStr -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-core/app/views/widgets/sparqlDatasetSelect.scala.html b/silk-workbench/silk-workbench-core/app/views/widgets/sparqlDatasetSelect.scala.html deleted file mode 100644 index 7c5cf26da8..0000000000 --- a/silk-workbench/silk-workbench-core/app/views/widgets/sparqlDatasetSelect.scala.html +++ /dev/null @@ -1,28 +0,0 @@ -@import org.silkframework.dataset.DatasetSpec.GenericDatasetSpec -@import org.silkframework.dataset.rdf.RdfDataset -@import org.silkframework.workspace.WorkspaceFactory - -@import org.silkframework.runtime.activity.UserContext -@(projectName: String, label: String, description: String, mainId: String, inputId: Option[String])(implicit userContext: UserContext) - -@project = @{ WorkspaceFactory().workspace.project(projectName.toString) } -@rdfDatasets = @{ project.tasks[GenericDatasetSpec].filter(_.data.plugin.isInstanceOf[RdfDataset]) } - -
- - -
- @description -
-
diff --git a/silk-workbench/silk-workbench-core/conf/core.routes b/silk-workbench/silk-workbench-core/conf/core.routes index c9bff987c7..404dc09a55 100644 --- a/silk-workbench/silk-workbench-core/conf/core.routes +++ b/silk-workbench/silk-workbench-core/conf/core.routes @@ -1,7 +1,5 @@ -GET /start controllers.core.Start.index GET /logo.png controllers.core.Branding.logo GET /logoSmall.png controllers.core.Branding.logoSmall -GET /aboutDialog controllers.core.Branding.aboutDialog GET /mdlStyle controllers.core.Branding.mdlStyle GET /config controllers.core.ConfigController.index GET /plugins controllers.core.PluginApi.plugins(addMarkdownDocumentation: Boolean ?= false) diff --git a/silk-workbench/silk-workbench-rules/app/controllers/linking/EvaluateLinkingController.scala b/silk-workbench/silk-workbench-rules/app/controllers/linking/EvaluateLinkingController.scala deleted file mode 100644 index 9d9ba3fff3..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/linking/EvaluateLinkingController.scala +++ /dev/null @@ -1,83 +0,0 @@ -package controllers.linking - -import akka.actor.ActorSystem -import akka.stream.Materializer -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import controllers.util.AkkaUtils -import models.linking.EvalLink.{Correct, Generated, Incorrect, Unknown} -import models.linking.{EvalLink, LinkResolver, LinkSorter} -import org.silkframework.rule.LinkSpec -import org.silkframework.rule.evaluation.DetailedEvaluator -import org.silkframework.runtime.activity.UserContext -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.linking.EvaluateLinkingActivity -import play.api.libs.json.Json -import play.api.mvc.{Action, AnyContent, InjectedController, WebSocket} - -import javax.inject.Inject - -class EvaluateLinkingController @Inject() (implicit system: ActorSystem, - mat: Materializer, - accessMonitor: WorkbenchAccessMonitor, - workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def generateLinks(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[LinkSpec](project, task, request.path) - accessMonitor.saveProjectTaskAccess(project, task) - Ok(views.html.evaluateLinking.evaluateLinking(context)) - } - - def links(projectName: String, taskName: String, sorting: String, filter: String, page: Int): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[LinkSpec](taskName) - val linkSorter = LinkSorter.fromId(sorting) - val linking = task.activity[EvaluateLinkingActivity].value() - val schemata = task.data.entityDescriptions - val linkResolvers = LinkResolver.forLinkingTask(task) - - // We only show links if entities have been attached to them. We check this by looking at the first link. - val showLinks = { - linking.links.headOption.flatMap(_.entities) match { - case Some(entities) => - // Check if the entities got all paths that are used in the linkage rule - schemata.source.typedPaths.forall(entities.source.schema.typedPaths.contains) && - schemata.target.typedPaths.forall(entities.target.schema.typedPaths.contains) - case None => false - } - } - - if(showLinks) { - val referenceLinks = task.data.referenceLinks - def links = - for (link <- linking.links.view) yield { - val detailedLink = DetailedEvaluator(task.data.rule, link.entities.get) - if (referenceLinks.positive.contains(link)) - new EvalLink(detailedLink, Correct, Generated) - else if (referenceLinks.negative.contains(link)) - new EvalLink(detailedLink, Incorrect, Generated) - else - new EvalLink(detailedLink, Unknown, Generated) - } - Ok(views.html.widgets.linksTable(project, task, links.toSeq, Some(linking.statistics), linkResolvers, linkSorter, filter, page, - showStatus = false, showDetails = true, showEntities = false, rateButtons = true)) - } else { - // Show an empty links table - Ok(views.html.widgets.linksTable(project, task, Seq[EvalLink](), Some(linking.statistics), linkResolvers, linkSorter, filter, - page, showStatus = false, showDetails = true, showEntities = false, rateButtons = true)) - } - } - - def linksWebsocket(projectName: String, taskName: String): WebSocket = { - implicit val userContext = UserContext.Empty - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[LinkSpec](taskName) - val activity = task.activity[EvaluateLinkingActivity] - - // Create a source that sends an empty object on every update - val source = AkkaUtils.createSource(activity.value).map(_ => Json.obj()) - AkkaUtils.createWebSocket(source) - } -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/linking/ExecuteLinkingController.scala b/silk-workbench/silk-workbench-rules/app/controllers/linking/ExecuteLinkingController.scala deleted file mode 100644 index 47640dbf3e..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/linking/ExecuteLinkingController.scala +++ /dev/null @@ -1,23 +0,0 @@ -package controllers.linking - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import org.silkframework.rule.LinkSpec -import org.silkframework.workbench.Context -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -class ExecuteLinkingController @Inject() (implicit workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def execute(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[LinkSpec](project, task, request.path) - Ok(views.html.executeLinking.executeLinking(context)) - } - - def executionReport(project: String, task: String): Action[AnyContent] = RequestUserContextAction { request =>implicit userContext => - val context = Context.get[LinkSpec](project, task, request.path) - Ok(views.html.executeLinking.linkingReport(context.task)) - } - -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/linking/LinkingEditor.scala b/silk-workbench/silk-workbench-rules/app/controllers/linking/LinkingEditor.scala deleted file mode 100644 index cae0146c34..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/linking/LinkingEditor.scala +++ /dev/null @@ -1,84 +0,0 @@ -package controllers.linking - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import org.silkframework.entity.EntitySchema -import org.silkframework.rule.LinkSpec -import org.silkframework.rule.evaluation.LinkageRuleEvaluator -import org.silkframework.util.DPair -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.linking.{LinkingPathsCache, ReferenceEntitiesCache} -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject -import scala.util.control.NonFatal - -class LinkingEditor @Inject() (implicit accessMonitor: WorkbenchAccessMonitor, workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def editor(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[LinkSpec](project, task, request.path) - accessMonitor.saveProjectTaskAccess(project, task) - Ok(views.html.editor.linkingEditor(context)) - } - - def paths(projectName: String, taskName: String, groupPaths: Boolean): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[LinkSpec](taskName) - val pathsCache = task.activity[LinkingPathsCache].control - val prefixes = project.config.prefixes - val sourceNames = task.data.dataSelections.map(s => project.anyTask(s.inputId.toString).label()) - - if(pathsCache.status().isRunning) { - val loadingMsg = f"Cache loading (${pathsCache.status().progress.getOrElse(0.0) * 100}%.1f%%)" - ServiceUnavailable(views.html.editor.paths(sourceNames, DPair.fill(Seq.empty), onlySource = false, loadingMsg = loadingMsg, project = project)) - } else if(pathsCache.status().failed) { - Ok(views.html.editor.paths(sourceNames, DPair.fill(Seq.empty), onlySource = false, warning = pathsCache.status().message + " Try reloading the paths.", project = project)) - } else { - - val entityDescs = Option(pathsCache.value()).getOrElse(DPair.fill(EntitySchema.empty)) - val paths = entityDescs.map(_.typedPaths.map(_.toUntypedPath.serialize()(prefixes))) - if (groupPaths) { - Ok(views.html.editor.paths(sourceNames, paths, onlySource = false, project = project)) - } else { - Ok(views.html.editor.pathsList(sourceNames, paths, onlySource = false, project = project)) - } - } - } - - def score(projectName: String, taskName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[LinkSpec](taskName) - val entitiesCache = task.activity[ReferenceEntitiesCache].control - - // If the entity cache is still loading - if(entitiesCache.status().isRunning) { - ServiceUnavailable(f"Cache loading (${entitiesCache.status().progress.getOrElse(0.0) * 100}%.1f%%)") - // If the cache loading failed - } else if(entitiesCache.status().failed) { - Ok(views.html.editor.score( - info = "No score available", - error = "No score available as loading the entities that are referenced by the reference links failed. " + - "Reason: " + entitiesCache.status().message)) - // If there are no reference links - } else if (entitiesCache.value().positiveLinks.isEmpty || entitiesCache.value().negativeLinks.isEmpty) { - Ok(views.html.editor.score( - info = "No score available", - error = "No score available as this project does not define any reference links.")) - // If everything needed for computing a score is available - } else { - try { - val result = LinkageRuleEvaluator(task.data.rule, entitiesCache.value()) - val score = f"Precision: ${result.precision}%.2f | Recall: ${result.recall}%.2f | F-measure: ${result.fMeasure}%.2f" - Ok(views.html.editor.score(score)) - } catch { - case NonFatal(ex) => - Ok(views.html.editor.score( - info = "No score could be computed", - error = ex.getMessage - )) - } - } - } -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/linking/ReferenceLinksManager.scala b/silk-workbench/silk-workbench-rules/app/controllers/linking/ReferenceLinksManager.scala deleted file mode 100644 index c651e7b51a..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/linking/ReferenceLinksManager.scala +++ /dev/null @@ -1,129 +0,0 @@ -package controllers.linking - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import models.linking.EvalLink._ -import models.linking.{EvalLink, LinkResolver, LinkSorter} -import org.silkframework.entity.{Entity, MinimalLink} -import org.silkframework.rule.LinkSpec -import org.silkframework.rule.evaluation.DetailedEvaluator -import org.silkframework.util.DPair -import org.silkframework.workbench.Context -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.linking.ReferenceEntitiesCache -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -class ReferenceLinksManager @Inject() (implicit workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def referenceLinksView(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[LinkSpec](project, task, request.path) - Ok(views.html.referenceLinks.referenceLinks(context)) - } - - def referenceLinks(projectName: String, - taskName: String, - linkType: String, - sorting: String, - filter: String, - page: Int): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[LinkSpec](taskName) - val referenceLinks = task.data.referenceLinks - def linkSpec = task.data - def linkageRule = linkSpec.rule - def entities = task.activity[ReferenceEntitiesCache].value() - val linkSorter = LinkSorter.fromId(sorting) - val linkResolvers = LinkResolver.forLinkingTask(task) - - // Checks if a pair of entities provides values for all paths in the current linkage rule - def hasPaths(entities: DPair[Entity]): Boolean = { - linkSpec.entityDescriptions.source.typedPaths.forall(entities.source.schema.typedPaths.contains) && - linkSpec.entityDescriptions.target.typedPaths.forall(entities.target.schema.typedPaths.contains) - } - - val links = linkType match { - case "positive" => { - for (link <- referenceLinks.positive.toSeq.view) yield entities.positiveLinkToEntities(link) match { - case Some(entities) if hasPaths(entities) => { - val evaluatedLink = DetailedEvaluator(linkageRule, entities, -1.0).get - - new EvalLink( - link = evaluatedLink, - correct = if (evaluatedLink.confidence.getOrElse(-1.0) >= 0.0) Correct else Incorrect, - linkType = Positive - ) - } - case _ => { - val cleanLink = new MinimalLink(link.source, link.target) - - new EvalLink( - link = cleanLink, - correct = Unknown, - linkType = Positive - ) - } - } - } - case "negative" => { - for (link <- referenceLinks.negative.toSeq.view) yield entities.negativeLinkToEntities(link) match { - case Some(entities) if hasPaths(entities) => { - val evaluatedLink = DetailedEvaluator(linkageRule, entities, -1.0).get - - new EvalLink( - link = evaluatedLink, - correct = if (evaluatedLink.confidence.getOrElse(-1.0) >= 0.0) Incorrect else Correct, - linkType = Negative - ) - } - case _ => { - val cleanLink = new MinimalLink(link.source, link.target) - - new EvalLink( - link = cleanLink, - correct = Unknown, - linkType = Negative - ) - } - } - } - case "unlabeled" => { - for (link <- referenceLinks.unlabeled.toSeq.view) yield entities.unlabeledLinkToEntities(link) match { - case Some(entities) if hasPaths(entities) => { - val evaluatedLink = DetailedEvaluator(linkageRule, entities, -1.0).get - - new EvalLink( - link = evaluatedLink, - correct = Unknown, - linkType = Unlabeled - ) - } - case _ => { - val cleanLink = new MinimalLink(link.source, link.target) - - new EvalLink( - link = cleanLink, - correct = Unknown, - linkType = Unlabeled - ) - } - } - } - } - - Ok(views.html.widgets.linksTable(project, task, links.toSeq, None, linkResolvers, linkSorter, filter, page, showStatus = true, showDetails = true, showEntities = false, rateButtons = false)) - } - - def addLinkDialog(project: String, task: String) = Action { - Ok(views.html.referenceLinks.addLinkDialog(project, task)) - } - - def importDialog(project: String, task: String) = Action { - Ok(views.html.referenceLinks.importDialog(project, task)) - } - - def removeLinksDialog(project: String, task: String) = Action { - Ok(views.html.referenceLinks.removeLinksDialog(project, task)) - } -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/transform/EvaluateTransform.scala b/silk-workbench/silk-workbench-rules/app/controllers/transform/EvaluateTransform.scala deleted file mode 100644 index 2830848824..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/transform/EvaluateTransform.scala +++ /dev/null @@ -1,53 +0,0 @@ -package controllers.transform - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import org.silkframework.rule.TransformSpec -import org.silkframework.rule.execution.{EvaluateTransform => EvaluateTransformTask} -import org.silkframework.runtime.plugin.PluginContext -import org.silkframework.runtime.validation.NotFoundException -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.transform.TransformTaskUtils._ -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -/** Endpoints for evaluating transform tasks */ -class EvaluateTransform @Inject() (implicit accessMonitor: WorkbenchAccessMonitor, workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def evaluate(project: String, task: String, ruleName: Option[String], offset: Int, limit: Int): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - accessMonitor.saveProjectTaskAccess(project, task) - Ok(views.html.evaluateTransform.evaluateTransform(context, ruleName.getOrElse("root"), offset, limit)) - } - - def generatedEntities(projectName: String, taskName: String, ruleName: Option[String], offset: Int, limit: Int): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - implicit val pluginContext: PluginContext = PluginContext.fromProject(project) - val task = project.task[TransformSpec](taskName) - val ruleSchema = ruleName match { - case Some(name) => - val objectMappingId = task.data.objectMappingIdOfRule(name).getOrElse(name) - task.data.ruleSchemataWithoutEmptyObjectRules - .find(_.transformRule.id.toString == objectMappingId) - .getOrElse(throw new NotFoundException(s"Mapping rule '$name' is either an empty object rule, i.e. it has at most a URI rule, or is not part of task '$taskName' in project '$projectName'.")) - case None => - task.data.ruleSchemataWithoutEmptyObjectRules.head - } - - // Create execution task - val evaluateTransform = - new EvaluateTransformTask( - source = task.dataSource, - entitySchema = ruleSchema.inputSchema, - rules = ruleSchema.transformRule.rules, - maxEntities = offset + limit - ) - val entities = evaluateTransform.execute().drop(offset) - - Ok(views.html.evaluateTransform.generatedEntities(entities, project.config.prefixes)) - } - -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/transform/ExecuteTransformTab.scala b/silk-workbench/silk-workbench-rules/app/controllers/transform/ExecuteTransformTab.scala deleted file mode 100644 index cf0f5d849a..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/transform/ExecuteTransformTab.scala +++ /dev/null @@ -1,26 +0,0 @@ -package controllers.transform - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions - -import javax.inject.Inject -import org.silkframework.rule.TransformSpec -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import play.api.mvc.{Action, AnyContent, InjectedController} - -/** Endpoints for the 'Execute' page of a transform task */ -class ExecuteTransformTab @Inject() (implicit accessMonitor: WorkbenchAccessMonitor, workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def execute(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - accessMonitor.saveProjectTaskAccess(project, task) - Ok(views.html.executeTransform.executeTransform(context)) - } - - def executionReport(project: String, task: String): Action[AnyContent] = RequestUserContextAction { request =>implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - Ok(views.html.executeTransform.transformReport(context.task)) - } - -} diff --git a/silk-workbench/silk-workbench-rules/app/controllers/transform/TransformEditor.scala b/silk-workbench/silk-workbench-rules/app/controllers/transform/TransformEditor.scala deleted file mode 100644 index 190b0ffaba..0000000000 --- a/silk-workbench/silk-workbench-rules/app/controllers/transform/TransformEditor.scala +++ /dev/null @@ -1,97 +0,0 @@ -package controllers.transform - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import controllers.core.util.ControllerUtilsTrait -import org.silkframework.entity.paths.UntypedPath -import org.silkframework.rule.TransformSpec -import org.silkframework.runtime.validation.NotFoundException -import org.silkframework.util.{DPair, Uri} -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.transform.{TransformPathsCache, VocabularyCacheValue} -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -class TransformEditor @Inject() (implicit accessMonitor: WorkbenchAccessMonitor, workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions with ControllerUtilsTrait { - - def start(project: String, task: String, rule: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - val vocabularies = VocabularyCacheValue.targetVocabularies(context.task) - accessMonitor.saveProjectTaskAccess(project, task) - - // TODO: We should check whether the rule exists - Ok(views.html.editor.transformRules(context, vocabularies, rule)) - } - - def editor(project: String, task: String, rule: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - val transformSpec = context.task.data - transformSpec.nestedRuleAndSourcePath(rule) match { - case Some((r, _)) => Ok(views.html.editor.transformEditor(context, r)) - case None => - val validRuleNames = transformSpec.ruleSchemata.map(_.transformRule.id).mkString(", ") - NotFound(s"No rule named '$rule' found!. Available rules: $validRuleNames") - } - } - - def propertyDetails(project: String, task: String, property: String): Action[AnyContent] = RequestUserContextAction { request => implicit userContext => - val context = Context.get[TransformSpec](project, task, request.path) - val vocabularies = VocabularyCacheValue.targetVocabularies(context.task) - val uri = Uri.parse(property, context.project.config.prefixes) - - Ok(views.html.editor.propertyDetails(property, vocabularies.findProperty(uri.uri), context.project.config.prefixes)) - } - - /** Fetch relative source paths for a specific rule and render widget. */ - def rulePaths(projectName: String, taskName: String, ruleName: String, groupPaths: Boolean): Action[AnyContent] = UserContextAction { implicit userContext => - val (project, transformTask) = projectAndTask[TransformSpec](projectName, taskName) - val sourceName = project.anyTask(transformTask.data.selection.inputId).label() - val prefixes = project.config.prefixes - transformTask.data.nestedRuleAndSourcePath(ruleName) match { - case Some((_, sourcePath)) => - val pathsCache = transformTask.activity[TransformPathsCache] - pathsCache.control.waitUntilFinished() - if(pathsCache.status().failed) { - Ok(views.html.editor.paths(DPair(sourceName, ""), DPair.fill(Seq.empty), onlySource = true, - warning = pathsCache.status().message, project = project)) - } else { - val relativePaths = pathsCache.value().configuredSchema.typedPaths. // FIXME: This won't work inside nested object rules for RDF datasets - filter(tp => tp.operators.startsWith(sourcePath) && tp.operators.size > sourcePath.size). - map(tp => UntypedPath(tp.operators.drop(sourcePath.size))) - val paths = DPair(relativePaths.map(_.serialize()(prefixes)), Seq.empty) - if (groupPaths) { - Ok(views.html.editor.paths(DPair(sourceName, ""), paths, onlySource = true, project = project)) - } else { - Ok(views.html.editor.pathsList(DPair(sourceName, ""), paths, onlySource = true, project = project)) - } - } - case None => - throw new NotFoundException("No rule found with name " + ruleName) - } - } - - def paths(projectName: String, taskName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.task[TransformSpec](taskName) - val pathsCache = task.activity[TransformPathsCache].control - val prefixes = project.config.prefixes - val sourceName = task.data.selection.inputId.toString - - if(pathsCache.status().isRunning) { - val loadingMsg = f"Cache loading (${pathsCache.status().progress.getOrElse(0.0) * 100}%.1f%%)" - ServiceUnavailable(views.html.editor.paths(DPair(sourceName, ""), DPair.fill(Seq.empty), onlySource = true, loadingMsg = loadingMsg, project = project)) - } else if(pathsCache.status().failed) { - Ok(views.html.editor.paths(DPair(sourceName, ""), DPair.fill(Seq.empty), onlySource = true, warning = pathsCache.status().message, project = project)) - } else { - val paths = DPair(pathsCache.value().configuredSchema.typedPaths.map(_.toUntypedPath.serialize()(prefixes)), Seq.empty) - Ok(views.html.editor.paths(DPair(sourceName, ""), paths, onlySource = true, project = project)) - } - } - - def score(projectName: String, taskName: String): Action[AnyContent] = Action { - Ok - } -} diff --git a/silk-workbench/silk-workbench-rules/app/views/dialogs/deleteRuleDialog.scala.html b/silk-workbench/silk-workbench-rules/app/views/dialogs/deleteRuleDialog.scala.html deleted file mode 100644 index 952ffa3fc4..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/dialogs/deleteRuleDialog.scala.html +++ /dev/null @@ -1,27 +0,0 @@ -@(ruleName: String) - -@widgets.dialog(title = "Delete", submitLabel = "Yes, delete it") { - -

- Delete rule: @ruleName -

-

This action cannot be undone!

- - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/GenerateId.scala b/silk-workbench/silk-workbench-rules/app/views/editor/GenerateId.scala deleted file mode 100644 index 1f1ca6e30c..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/GenerateId.scala +++ /dev/null @@ -1,20 +0,0 @@ -package views.editor - -/** - * Generates a unique id for a rule operator to be used in the editor html. - */ -object GenerateId { - - /** - * Generates a unique id. - * @param operatorId The id of the rule operator, which is unique inside the rule. - * @param displayed Whether the rule is displayed, or hidden in the toolbox. - */ - def apply(operatorId: String, displayed: Boolean): String = { - if(displayed) - "operator_" + operatorId - else - "toolboxOperator_" + operatorId - } - -} diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/aggregationBox.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/aggregationBox.scala.html deleted file mode 100644 index c8c245535a..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/aggregationBox.scala.html +++ /dev/null @@ -1,22 +0,0 @@ -@import views.editor.GenerateId -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@(id: String, - weight: Int, - plugin: org.silkframework.runtime.plugin.PluginDescription[_], - parameterValues: Seq[String], - x: Int, y: Int, display: Boolean, - project: Project)(implicit userContext: UserContext) - -@operatorBox("Aggregate", id, plugin, parameterValues, x, y, display, project) { -
- -
- The weight parameter can be used by the parent aggregation when combining - its input values. Only certain aggregations will consider weighted inputs. Examples are the weighted average - aggregation, quadraticMean and geometricMean. -
- -
-} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/comparisonBox.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/comparisonBox.scala.html deleted file mode 100644 index 624dee115b..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/comparisonBox.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@import views.editor.GenerateId -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@(id: String, - weight: Int, threshold: Double, - plugin: org.silkframework.runtime.plugin.PluginDescription[_], - parameterValues: Seq[String], - x: Int, y: Int, display: Boolean, - project: Project)(implicit userContext: UserContext) - -@operatorBox("Compare", id, plugin, parameterValues, x, y, display, project) { -
- -
- The maximum distance. For normalized distance measures, the threshold should be between 0.0 and 1.0. -
- -
-
- -
- The weight parameter can be used by the parent aggregation when combining - its input values. Only certain aggregations will consider weighted inputs. Examples are the weighted average - aggregation, quadraticMean and geometricMean. -
- -
-} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/linkingEditor.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/linkingEditor.scala.html deleted file mode 100644 index 30fe85d5fd..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/linkingEditor.scala.html +++ /dev/null @@ -1,180 +0,0 @@ -@import org.silkframework.rule.input.Transformer -@import org.silkframework.rule.similarity.Aggregator -@import org.silkframework.rule.similarity.DistanceMeasure -@import controllers.workspace.routes -@import controllers.rules.routes.Assets -@import controllers.core.routes.{Assets => CoreAssets} -@import org.silkframework.rule.LinkSpec -@import org.silkframework.workbench.Context -@import org.silkframework.runtime.activity.UserContext - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[LinkSpec])(implicit request: RequestHeader, userContext: UserContext, workspaceReact: WorkspaceReact) - -@header = { - - - - - - - - - - - - - -} - -@toolbar = { -
    -
  • - -
  • -
  • - -
  • -
  • -
    -
  • -
  • - -
    - Reload paths -
    -
  • -
  • - - file_download - -
    - Get Link Specification to be executed from the command line -
    -
  • -
  • -
    -
  • -
  • - - -
    - Defines the number of links (n) originating from a single data item. Only the n highest-rated links per source data item will remain after the filtering. -
    -
  • -
  • -
    -
  • -
  • - - -
  • -
- - @status() - -
@* Filled by updateScore() *@
-} - -@content = { -
-
-
- - -
-
- -
-
-
loading ...
- -
- -
- @operators("Transformations", "transform", Transformer.pluginsByCategory, context.project) - @operators("Comparators", "compare", DistanceMeasure.pluginsByCategory, context.project) - @operators("Aggregators", "aggregate", Aggregator.pluginsByCategory, context.project) -
-
- - -
- - - -
- -
- -
- @context.task.data.rule.operator match { - case Some(op) => { - @renderRule( - rule = op, - project = context.project - ) - } - case None => { - - } - } -
- -
- -
-} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/operatorBox.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/operatorBox.scala.html deleted file mode 100644 index d2d4595931..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/operatorBox.scala.html +++ /dev/null @@ -1,114 +0,0 @@ -@import controllers.rules.routes.Assets -@import views.editor.GenerateId -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.plugin.PluginParameter -@import org.silkframework.runtime.plugin.StringParameterType._ -@import org.silkframework.workspace.WorkspaceFactory -@import org.silkframework.runtime.activity.UserContext - -@(opType: String, - id: String, - plugin: org.silkframework.runtime.plugin.PluginDescription[_], - parameterValues: Seq[String], - x: Int, y: Int, - display: Boolean, - project: Project)(additionalContent: Html)(implicit userContext: UserContext) - -
- @plugin.id - @opType -
- - - - -
- Remove operator -
-
- @plugin.description -
-
-
- @additionalContent - @for((param, value) <- plugin.parameters zip parameterValues) { -
- @parameter(param, value) -
- } -
- -
- -@** -* Creates a new field for a plugin parameter -*@ -@parameter(param: PluginParameter, value: String) = @{ - param.parameterType match { - case UriType => - stringParameter(param, project.config.prefixes.shorten(value)) - case enum: EnumerationType => - enumParameter(param, enum.enumerationValues, enum.displayNames, value) - case BooleanType => - enumParameter(param, Seq("true", "false"), Seq("True", "False"), value) - case ResourceType | WritableResourceType => - val resources = project.resources.listRecursive - enumParameter(param, resources, resources, value) - case ProjectReferenceType => - val projectNames = WorkspaceFactory().workspace.userProjects.map(_.id.toString) - enumParameter(param, projectNames, projectNames, value) - case TaskReferenceType => - val taskNames = project.allTasks.map(_.id.toString) - enumParameter(param, taskNames, taskNames, value) - case MultilineStringParameterType => - multilineParameter(param, value) - case _ => - stringParameter(param, value) - } -} - -@multilineParameter(param: PluginParameter, value: String) = { -@* broken: widgets.multilineParameter(GenerateId(id, display), value, label = param.label, tooltip = param.description, additionalInputElementsClass = "param_value") *@ -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - -@stringParameter(param: PluginParameter, value: String) = { -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - -@enumParameter(param: PluginParameter, enumerationValues: Seq[String], displayNames: Seq[String], value: String) = { -
- - -
- @param.description -
- Expected type: @param.parameterType.description -
-
-} - - diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/operators.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/operators.scala.html deleted file mode 100644 index 87f1ab1e50..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/operators.scala.html +++ /dev/null @@ -1,112 +0,0 @@ -@import org.silkframework.runtime.plugin.PluginDescription -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.runtime.plugin.PluginCategories - -@import org.silkframework.runtime.plugin.PluginContext -@(name: String, - opType: String, - pluginsByCategory: Map[String, Seq[org.silkframework.runtime.plugin.PluginDescription[_]]], - project: Project)(implicit userContext: UserContext) - - - -
-
- @name -
- -
-
- -
- @for((category, plugins) <- pluginsByCategory) { - - } -
-
- -@** - * A single operator in the toolbox. - *@ -@operatorIcon(plugin: PluginDescription[_], category: String) = { -
- - @plugin.label -

@plugin.label

- @operatorExpanded(plugin) -
-
- @plugin.description -
-} - -@operatorExpanded(plugin: PluginDescription[_]) = { - @opType match { - case "transform" => { @transformationBox(plugin.id, plugin, parameterValues(plugin), 0, 0, false, project) } - case "compare" => { @comparisonBox(plugin.id, 1, 0.0, plugin, parameterValues(plugin), 0, 0, false, project) } - case "aggregate" => { @aggregationBox(plugin.id, 1, plugin, parameterValues(plugin), 0, 0, false, project) } - } -} - -@parameterValues(plugin: PluginDescription[_]) = @{ - implicit val prefixes = project.config.prefixes - for(p <- plugin.parameters) yield p.stringDefaultValue(PluginContext.empty).getOrElse("") -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/operatorsAll.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/operatorsAll.scala.html deleted file mode 100644 index 50bb40cc38..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/operatorsAll.scala.html +++ /dev/null @@ -1,39 +0,0 @@ -@import org.silkframework.runtime.plugin.PluginDescription -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@import org.silkframework.runtime.plugin.PluginContext -@(name: String, -opType: String, -pluginGroup: org.silkframework.runtime.plugin.PluginFactory[_], -project: Project)(implicit userContext: UserContext) - -@for(plugin <- pluginGroup.availablePlugins) { -
-
- @plugin.label -
-
- @plugin.label -

@plugin.label

- @operatorExpanded(plugin) -
-
- @plugin.description -
-
-} - -@* Need to generate different IDs as for the main operators. Since the IDs are used for generating labels after dragging the operator in, we just add a _ *@ -@operatorExpanded(plugin: PluginDescription[_]) = { - @opType match { - case "transform" => { @transformationBox(plugin.id + "_", plugin, parameterValues(plugin), 0, 0, false, project) } - case "compare" => { @comparisonBox(plugin.id + "_", 1, 0.0, plugin, parameterValues(plugin), 0, 0, false, project) } - case "aggregate" => { @aggregationBox(plugin.id + "_", 1, plugin, parameterValues(plugin), 0, 0, false, project) } - } -} - -@parameterValues(plugin: PluginDescription[_]) = @{ - implicit val prefixes = project.config.prefixes - for(p <- plugin.parameters) yield p.stringDefaultValue(PluginContext.empty).getOrElse("") -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/pathBox.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/pathBox.scala.html deleted file mode 100644 index c284309283..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/pathBox.scala.html +++ /dev/null @@ -1,23 +0,0 @@ -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext -@import scala.collection.immutable.ListMap - -@(id: String, - isSource: Boolean, - path: String, - x: Int, y: Int, display: Boolean, - project: Project)(implicit userContext: UserContext) - -@import org.silkframework.runtime.plugin.ClassPluginDescription - -@operatorBox( - opType = if(isSource) "Source" else "Target", - id = id, - plugin = new ClassPluginDescription(id, Seq.empty, "Path", "Path", "", Seq.empty, null, Seq.empty, None, ListMap.empty, None, Seq.empty), - parameterValues = Seq.empty, - x = x, - y = y, - display = display, - project = project) { - - } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/paths.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/paths.scala.html deleted file mode 100644 index 35459a8ab5..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/paths.scala.html +++ /dev/null @@ -1,114 +0,0 @@ -@import org.silkframework.util.DPair -@import org.silkframework.workspace.Project -@import controllers.rules.routes.Assets - -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.util.Identifier - -@(sources: DPair[String], paths: DPair[Seq[String]], onlySource: Boolean, loadingMsg: String = "", - warning: String = "", project: Project)(implicit userContext: UserContext) - - - -@pathOperators(sources.source, paths.source, "Source") -@if(!onlySource) { - @pathOperators(sources.target, paths.target, "Target") -} - -@pathOperators(source: String, paths: Seq[String], pathType: String) = { - - @*Maximum Paths that should be rendered by default*@ - @defining(20) { maximumPaths => - -
-
- @pathType paths: - @source -
- -
-
- - -

(custom path)

- @pathExpanded("", pathType) -
- - @loadingMsg - @if(!warning.isEmpty) { } - - @for((path, index) <- paths.zipWithIndex) { - -
- @path -
- } - @if(paths.length > maximumPaths) { -
- Show all @{pathType} Paths -
- } -
-
- } - -} - -@pathExpanded(path: String, pathType: String) = { - @pathBox(pathType.toLowerCase + "Path", pathType == "Source", path, 0, 0, false, project) -} - -@pathId(pathType: String, path: String) = {path_@{pathType.toLowerCase}_@{Identifier.fromAllowed(path, Some("empty")).toString}} - - diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/pathsList.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/pathsList.scala.html deleted file mode 100644 index 1e341e82b9..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/pathsList.scala.html +++ /dev/null @@ -1,34 +0,0 @@ -@import org.silkframework.util.DPair -@import org.silkframework.workspace.Project - -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.util.Identifier - -@(sources: DPair[String], paths: DPair[Seq[String]], onlySource: Boolean, loadingMsg: String = "", warning: String = "", - project: Project)(implicit userContext: UserContext) - -@pathOperators(sources.source, paths.source, "Source") -@pathOperators(sources.target, paths.target, "Target") - -@pathOperators(source: String, paths: Seq[String], pathType: String) = { - @for(path <- paths) { -
-
- @path -
-
-

@path

- @pathExpanded(path, pathType) -
-
- @path -
-
- } -} - -@pathExpanded(path: String, pathType: String) = { - @pathBox(pathType.toLowerCase + "Path", pathType == "Source", path, 0, 0, false, project) -} - -@pathId(pathType: String, path: String) = {path_@{pathType.toLowerCase}_@{Identifier.fromAllowed(path).toString}} diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/propertyDetails.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/propertyDetails.scala.html deleted file mode 100644 index b7a25d5fc2..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/propertyDetails.scala.html +++ /dev/null @@ -1,49 +0,0 @@ -@import org.silkframework.rule.vocab.VocabularyProperty -@import org.silkframework.config.Prefixes - -@* -* Shows details information for a vocabulary property. -*@ -@(name: String, property: Option[VocabularyProperty], prefixes: Prefixes = Prefixes.default) - -@property match { - case Some(prop) => { @renderProperty(prop) } - case None => { Property @name not found in target vocabularies. } -} - -@renderProperty(prop: VocabularyProperty) = { -
-
@renderPropertyName(prop) (@renderPropertyDomain(prop), @renderPropertyRange(prop))
-
- @renderPropertyDescription(prop) -
-
-} - -@renderPropertyName(prop: VocabularyProperty) = { - @prop.info.label match { - case Some(label) => { @label } - case None => { no label } - } -} - -@renderPropertyDescription(prop: VocabularyProperty) = { - @prop.info.description match { - case Some(desc) => { @desc } - case None => { no description } - } -} - -@renderPropertyDomain(prop: VocabularyProperty) = { - @prop.domain match { - case Some(domain) => { @prefixes.shorten(domain.info.uri) } - case None => { (unspecified) } - } -} - -@renderPropertyRange(prop: VocabularyProperty) = { - @prop.range match { - case Some(range) => { @prefixes.shorten(range.info.uri) } - case None => { (unspecified) } - } -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/renderRule.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/renderRule.scala.html deleted file mode 100644 index 7c181cf9a9..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/renderRule.scala.html +++ /dev/null @@ -1,203 +0,0 @@ -@import org.silkframework.rule.Operator -@import org.silkframework.rule.input.TransformInput -@import org.silkframework.rule.input.PathInput -@import org.silkframework.rule.similarity.Aggregation -@import org.silkframework.rule.similarity.Comparison -@import org.silkframework.rule.RuleTraverser -@import org.silkframework.runtime.plugin.PluginDescription -@import views.editor.GenerateId -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@import org.silkframework.runtime.plugin.PluginContext -@(rule: org.silkframework.rule.Operator, - project: Project)(implicit userContext: UserContext) - -@drawLevel(Seq(rule), (countLevels(rule) - 1) * 250, maxWidth(rule) * 200) - -@connectOperators(rule) - -@drawLevel(ops: Seq[Operator], x: Int, height: Int) = { - @if(!ops.isEmpty) { - @for((op, index) <- ops.zipWithIndex) { - @drawOperator(op, x + 20, height * (index + 1) / (ops.size + 1) - 80) - } - @drawLevel(ops.flatMap(getChildren), x - 250, height) - } -} - -@countLevels(op: Operator) = @{ - def count(op: Operator): Int = { - val children = getChildren(op) - if(children.isEmpty) - 1 - else - 1 + children.map(count).max - } - count(op) -} - -@maxWidth(op: Operator) = @{ - def findMax(ops: Seq[Operator]): Int = { - val children = ops.flatMap(getChildren) - if(children.isEmpty) - ops.size - else - Seq(ops.size, findMax(children)).max - } - findMax(Seq(op)) -} - -@getChildren(op: Operator) = @{ - op match { - case agg: Aggregation => agg.operators - case cmp: Comparison => cmp.inputs.toSeq - case transform: TransformInput => transform.inputs - case path: PathInput => Seq.empty - } -} - -@drawOperator(op: Operator, x: Int, y: Int) = { - @op match { - case Aggregation(id, weight, aggregator, operators) => { - @aggregationBox(id, weight, aggregator.pluginSpec, parameterValues(aggregator, aggregator.pluginSpec), x, y, true, project) - } - case Comparison(id, weight, threshold, indexing, metric, inputs) => { - @comparisonBox(id, weight, threshold, metric.pluginSpec, parameterValues(metric, metric.pluginSpec), x, y, true, project) - } - case TransformInput(id, transformer, inputs) => { - @transformationBox(id, transformer.pluginSpec, parameterValues(transformer, transformer.pluginSpec), x, y, true, project) - } - case PathInput(id, path) => { - @pathBox(id, isSourceInput(op), path.serialize()(project.config.prefixes), x, y, true, project) - } - } -} - -@parameterValues(plugin: AnyRef, pluginType: PluginDescription[_]) = @{ - for(p <- pluginType.parameters) yield p.stringValue(plugin)(PluginContext.fromProject(project)) -} - -@** - * Determines if an operator is a source or target input. - *@ -@isSourceInput(op: Operator) = @{ - var isSource = true - for { - // Get a traversable node for the given operator - inputNode <- RuleTraverser(rule).iterateAllChildren.find(_.operator.id == op.id) - // Find the root input, i.e., the one directly below a comparison - rootInputNode <- inputNode.iterateParents.find(_.moveUp.exists(_.operator.isInstanceOf[Comparison])) - // Get the comparison node - comparisonNode <- rootInputNode.moveUp - } { - // The operator is a source input if it is the first child of the comparison - isSource = comparisonNode.iterateChildren.next().operator.id == rootInputNode.operator.id - } - isSource -} - -@connectOperators(op: Operator) = { - -} - -@connectOperator(op: Operator) = { - @op match { - case Aggregation(id, weight, aggregator, operators) => { - @* Handle children *@ - @for(op <- operators) { - @connectOperator(op) - } - - @* Create endpoints *@ - var @targetEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointSimilarityTarget); - var @sourceEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointSimilaritySource); - - @* Connect children *@ - @for(op <- operators) { - jsPlumb.connect({ - source: @sourceEndpoint(op.id), - target: @targetEndpoint(id) - }); - } - } - case Comparison(id, weight, threshold, indexing, metric, inputs) => { - @* Handle children *@ - @connectOperator(inputs.source) - @connectOperator(inputs.target) - - @* Create endpoints *@ - var @targetEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointValueTarget); - var @sourceEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointSimilaritySource); - - @* Connect children *@ - jsPlumb.connect({ - source: @sourceEndpoint(inputs.source.id), - target: @targetEndpoint(id) - }); - jsPlumb.connect({ - source: @sourceEndpoint(inputs.target.id), - target: @targetEndpoint(id) - }); - } - case TransformInput(id, transformer, inputs) => { - @* Handle children *@ - @for(input <- inputs) { - @connectOperator(input) - } - - var @targetEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointValueTarget); - var @sourceEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointValueSource); - - @* Connect children *@ - @for(input <- inputs) { - jsPlumb.connect({ - source: @sourceEndpoint(input.id), - target: @targetEndpoint(id) - }); - } - } - case PathInput(id, path) => { - var @sourceEndpoint(id) = jsPlumb.addEndpoint('@GenerateId(id,true)', endpointValueSource); - } - } -} - -@sourceEndpoint(id: String) = @{ - "endpoint_" + id.replace('-', '$') + "_source" -} - -@targetEndpoint(id: String) = @{ - "endpoint_" + id.replace('-', '$') + "_target" -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/score.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/score.scala.html deleted file mode 100644 index c558b845ab..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/score.scala.html +++ /dev/null @@ -1,15 +0,0 @@ -@(info: String = "", error: String = "") - -@import controllers.rules.routes.Assets - -@if(!info.isEmpty) { @info } -@if(!error.isEmpty) { } - -@* - -*@ \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/status.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/status.scala.html deleted file mode 100644 index dee858de1f..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/status.scala.html +++ /dev/null @@ -1,19 +0,0 @@ -@* - * A small toolbar icon that displays the current status of the editor. - * Displays messages and errors in the current rule. - * - * Messages are added using the following function: - * updateStatus(errorMessages, warningMessages, infoMessages) - * - *@ -@() - -
-
done
-
Validated successfully.
-
- - -
-
Errors.
-
diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/transformEditor.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/transformEditor.scala.html deleted file mode 100644 index 5be5df7d23..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/transformEditor.scala.html +++ /dev/null @@ -1,212 +0,0 @@ -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.rules.routes.Assets -@import org.silkframework.entity.ValueType -@import org.silkframework.rule.{TransformRule, TransformSpec, MappingTarget} -@import org.silkframework.runtime.serialization.XmlSerialization.toXml -@import org.silkframework.workbench.Context -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.rule.input.Transformer - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[TransformSpec], rule: TransformRule)(implicit request: RequestHeader, userContext: UserContext, workspaceReact: WorkspaceReact) - -@header = { - - - - - - - - - - - - - @** As the editor does not manage the meta data and mapping target, we just hold it and attach it to updated rules. **@ - - - - - -} - -@toolbar = { -
    -
  • - - arrow_back - -
  • -
  • -
    -
  • -
  • - -
  • -
  • - -
  • -
  • -
    -
  • -
  • - -
    - Reload Property Paths -
    -
  • -
  • -
    -
  • -
  • - -
    - -
    -
    - The name of this transformation rule. -
    -
  • -
  • -
    -
  • - @if(rule.metaData.label.nonEmpty) { -
  • -
    -
    Label
    -
    @rule.metaData.formattedLabel("")
    -
    -
  • - } - @for(mappingTarget <- rule.target) { -
  • -
    -
    Target property
    -
    @mappingTarget.propertyUri.serialize(context.project.config.prefixes)
    -
    -
  • -
  • -
    -
    Target type
    -
    @mappingTarget.valueType.label
    -
    -
  • - } -
  • - -
    - -
    -
    - The target property. -
    -
  • -
  • - -
    - -
    -
    - The target type. -
    -
  • -
  • - -
    - -
    -
    - Write as attribute. -
    -
  • -
- - @status() - -
@* Filled by updateScore() *@
-} - -@content = { -
-
-
- - -
-
- -
-
-
loading ...
- -
- -
- @operators("Transformations", "transform", Transformer.pluginsByCategory, context.project) -
-
- - -
- - - - -
- -
- -
- @renderRule( - rule = rule.operator, - project = context.project - ) -
- -
- -
-} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/transformRules.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/transformRules.scala.html deleted file mode 100644 index 5c9a364d01..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/transformRules.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@import config.WorkbenchConfig.WorkspaceReact -@import org.silkframework.rule.TransformSpec -@import org.silkframework.rule.vocab.Vocabularies -@import org.silkframework.workbench.Context -@(context: Context[TransformSpec], vocabularies: Vocabularies, rule: String)(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { -} - -@content = { - @coreLinks.mainJs() -
- - -} - -@main(Some(context), titleLabel = context.task.label())(header)(null)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/editor/transformationBox.scala.html b/silk-workbench/silk-workbench-rules/app/views/editor/transformationBox.scala.html deleted file mode 100644 index 14c2cd6eaa..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/editor/transformationBox.scala.html +++ /dev/null @@ -1,10 +0,0 @@ -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@(id: String, - plugin: org.silkframework.runtime.plugin.PluginDescription[_], - parameterValues: Seq[String], - x: Int, y: Int, display: Boolean, - project: Project)(implicit userContext: UserContext) - -@operatorBox("Transform", id, plugin, parameterValues, x, y, display, project) { } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/evaluateLinking/evaluateLinking.scala.html b/silk-workbench/silk-workbench-rules/app/views/evaluateLinking/evaluateLinking.scala.html deleted file mode 100644 index 93a6de9051..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/evaluateLinking/evaluateLinking.scala.html +++ /dev/null @@ -1,104 +0,0 @@ -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.rules.routes.Assets -@import controllers.workspace.routes.WorkspaceApi -@import controllers.workspace.routes.ActivityApi -@import controllers.linking.routes.EvaluateLinkingController -@import org.silkframework.rule.execution.GenerateLinks -@import org.silkframework.rule.LinkSpec -@import org.silkframework.workbench.Context -@import views.html.workspace.activity.taskActivityControl -@import org.silkframework.workspace.activity.linking.EvaluateLinkingActivity -@import org.silkframework.workspace.activity.linking.EvaluateLinkingFactory -@import config.WorkbenchConfig - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[LinkSpec])(implicit session: play.api.mvc.Session, request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - - - - - - - - - - - -} - -@toolbar = { -
    -
  • - @taskActivityControl(context.task.activity[EvaluateLinkingActivity], showButtons = true) -
  • -
-} - -@content = { -
-
- -
-
- -
- Expand all -
- -
- Collapse all -
- -
-
- -
-
- Filter: - -
-
-
- - - -
-
-} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/evaluateTransform.scala.html b/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/evaluateTransform.scala.html deleted file mode 100644 index 1f7fab07f3..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/evaluateTransform.scala.html +++ /dev/null @@ -1,31 +0,0 @@ -@import org.silkframework.rule.TransformSpec -@import controllers.rules.routes.Assets -@import controllers.core.routes.{Assets => CoreAssets} -@import org.silkframework.workbench.Context - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[TransformSpec], selectedRule: String, offset: Int, limit: Int)(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - -} - -@content = { -
- @coreLinks.mainJs() - -} - -@main(Some(context), titleLabel = context.task.label())(header)(null)(content) \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/generatedEntities.scala.html b/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/generatedEntities.scala.html deleted file mode 100644 index 2d4a96da43..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/evaluateTransform/generatedEntities.scala.html +++ /dev/null @@ -1,133 +0,0 @@ -@import org.silkframework.config.Prefixes -@import org.silkframework.rule.evaluation.{DetailedEntity, Value, TransformedValue, InputValue} -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.rules.routes.Assets -@import java.util.UUID -@import org.silkframework.entity.ValueType -@import org.silkframework.rule.MappingTarget - -@import config.WorkbenchConfig.WorkspaceReact -@(entities: Seq[org.silkframework.rule.evaluation.DetailedEntity], prefixes: Prefixes)(implicit workspaceReact: WorkspaceReact) - -@frame { - - - - -} { -
-
-
-
- Expand All -
-
-
- Collapse All -
-
-
- -
- @renderHeader - @for((entity, index) <- entities.zipWithIndex) { - @renderEntity(entity, index) - } -
- -} - -@renderHeader = { -
-
- Transformed Entities -
-
-} - -@renderEntity(entity: DetailedEntity, counter: Int) = { -
-
- @renderUris(entity.uris) -
- -
-} - -@renderUris(uris: Seq[String]) = { - @if(uris.isEmpty) { - @renderError("The URI pattern did not generate any URI for this entity.") - } else { - @uris.map(uri => prefixes.shorten(uri)).mkString(", ") - } -} - -@renderTarget(mappingTarget: Option[MappingTarget]) = { - @mappingTarget match { - case None => { - URI - } - case Some(target) => { - @target.propertyUri.serialize(prefixes) - @if(target.valueType != ValueType.UNTYPED) { - (@target.valueType.label) - } - } - } -} - -@renderValue(value: Value) = { @value match { - case TransformedValue(transform, values, children, error) => { -
  • - - Transform: @transform.transformer.pluginSpec.id (@transform.id) - @values.map(v => {v}) - @renderErrorOpt(value.formattedErrorMessage) - - @if(children.nonEmpty) { -
      - @children.map(v => renderValue(v)) -
    - } -
  • - } - case InputValue(input, values, error) => { -
  • - - Input: @input.path.serialize()(prefixes) (@input.id) - @values.map(v => {v}) - @renderErrorOpt(value.formattedErrorMessage) - -
  • - } -}} - -@renderErrorOpt(error: Option[String]) = { - @for(ex <- error) { - @renderError(ex) - } -} - -@renderError(error: String, id: String = UUID.randomUUID.toString) = { - - - -
    - @for(line <- error.split("\n")) { -

    @line

    - } -
    -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/executeLinking/executeLinking.scala.html b/silk-workbench/silk-workbench-rules/app/views/executeLinking/executeLinking.scala.html deleted file mode 100644 index 396f9d3373..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/executeLinking/executeLinking.scala.html +++ /dev/null @@ -1,38 +0,0 @@ -@import org.silkframework.rule.execution.ExecuteTransform -@import views.html.workspace.activity.taskActivityControl -@import org.silkframework.workbench.Context -@import org.silkframework.workspace.activity.linking.ExecuteLinking -@import org.silkframework.rule.LinkSpec -@import controllers.workspace.routes.TaskDownloadApi -@import controllers.linking.routes.ExecuteLinkingController -@import views.html.workspace.activity.autoReload -@import org.silkframework.workspace.activity.linking.ExecuteLinkingFactory -@import config.WorkbenchConfig.WorkspaceReact - -@(context: Context[LinkSpec])(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { -} - -@toolbar = { -
      -
    • - @taskActivityControl(context.task.activity[ExecuteLinking], showButtons = true) -
    • -
    • - - file_download - -
    • -
    -} - -@content = { - @autoReload( - context = context, - contentPath = ExecuteLinkingController.executionReport(context.project.id, context.task.id).url, - activityId = ExecuteLinkingFactory.pluginId - ) -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/executeLinking/linkingReport.scala.html b/silk-workbench/silk-workbench-rules/app/views/executeLinking/linkingReport.scala.html deleted file mode 100644 index 798ffda00e..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/executeLinking/linkingReport.scala.html +++ /dev/null @@ -1,21 +0,0 @@ -@import controllers.core.routes.{Assets => CoreAssets} -@import org.silkframework.workspace.ProjectTask -@import org.silkframework.rule.LinkSpec - -@import config.WorkbenchConfig.WorkspaceReact -@(task: ProjectTask[LinkSpec])(implicit workspaceReact: WorkspaceReact) - -
    - @coreLinks.mainJs() - -
    -
    diff --git a/silk-workbench/silk-workbench-rules/app/views/executeTransform/executeTransform.scala.html b/silk-workbench/silk-workbench-rules/app/views/executeTransform/executeTransform.scala.html deleted file mode 100644 index 2be2359008..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/executeTransform/executeTransform.scala.html +++ /dev/null @@ -1,39 +0,0 @@ -@import org.silkframework.rule.execution.ExecuteTransform -@import views.html.workspace.activity.taskActivityControl -@import controllers.transform.routes.ExecuteTransformTab -@import org.silkframework.rule.TransformSpec -@import controllers.workspace.routes.TaskDownloadApi -@import org.silkframework.workbench.Context -@import controllers.core.routes.{Assets => CoreAssets} -@import org.silkframework.workspace.activity.transform.ExecuteTransformFactory -@import views.html.workspace.activity.autoReload - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[TransformSpec])(implicit session: play.api.mvc.Session, request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { -} - -@toolbar = { -
      -
    • - @taskActivityControl(context.task.activity[ExecuteTransform], showButtons = true) -
    • -
    • - - file_download - -
    • -
    -} - -@content = { - @coreLinks.mainJs() - @autoReload( - context = context, - contentPath = ExecuteTransformTab.executionReport(context.project.id, context.task.id).url, - activityId = ExecuteTransformFactory.pluginId - ) -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/executeTransform/transformReport.scala.html b/silk-workbench/silk-workbench-rules/app/views/executeTransform/transformReport.scala.html deleted file mode 100644 index 95e46a13f3..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/executeTransform/transformReport.scala.html +++ /dev/null @@ -1,28 +0,0 @@ -@import org.silkframework.rule.execution.TransformReport -@import org.silkframework.rule.execution.TransformReport.RuleResult -@import org.silkframework.rule.execution.TransformReport.RuleError -@import org.silkframework.rule.TransformSpec -@import org.silkframework.config.Prefixes -@import org.silkframework.config.Task -@import org.silkframework.workbench.Context -@import org.silkframework.rule.TransformRule -@import controllers.core.routes.{Assets => CoreAssets} -@import org.silkframework.workspace.ProjectTask - -@import config.WorkbenchConfig.WorkspaceReact -@(task: ProjectTask[TransformSpec])(implicit workspaceReact: WorkspaceReact) - -
    - @coreLinks.mainJs() - -
    -
    diff --git a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/addLinkDialog.scala.html b/silk-workbench/silk-workbench-rules/app/views/referenceLinks/addLinkDialog.scala.html deleted file mode 100644 index a0d300da35..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/addLinkDialog.scala.html +++ /dev/null @@ -1,50 +0,0 @@ -@(project: String, task: String) - -@widgets.dialog(title = "Add Reference Links", width = 500) { - - - - - - - - - - - - - -
    Source - -
    Target - -
    Type - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/importDialog.scala.html b/silk-workbench/silk-workbench-rules/app/views/referenceLinks/importDialog.scala.html deleted file mode 100644 index 4e0b74eee4..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/importDialog.scala.html +++ /dev/null @@ -1,46 +0,0 @@ -@(project: String, task: String) - -@widgets.dialog(title = "Import Reference Links", width = 500) { - - - - - - - - - -
    File -
    - -
    -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/referenceLinks.scala.html b/silk-workbench/silk-workbench-rules/app/views/referenceLinks/referenceLinks.scala.html deleted file mode 100644 index f8e35d1140..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/referenceLinks.scala.html +++ /dev/null @@ -1,109 +0,0 @@ -@import org.silkframework.workspace.activity.linking.ReferenceEntitiesCache -@import views.html.workspace.activity.taskActivityControl -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.rules.routes.Assets -@import controllers.linking.routes -@import org.silkframework.rule.LinkSpec -@import org.silkframework.workbench.Context - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[LinkSpec])(implicit session: play.api.mvc.Session, request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - - - - - - - - - - - -} - -@toolbar = { -
      -
    • - -
    • -
    • -
      -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - - help_outline - -
    • -
    • -
      -
    • -
    • - @taskActivityControl(context.task.activity[ReferenceEntitiesCache], showButtons = true) -
    • -
    -} - -@content = { -
    -
    - -
    - -
    - -
    -
    - Filter: - -
    -
    -
    - - - -
    -
    -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/removeLinksDialog.scala.html b/silk-workbench/silk-workbench-rules/app/views/referenceLinks/removeLinksDialog.scala.html deleted file mode 100644 index 773923e1e8..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/referenceLinks/removeLinksDialog.scala.html +++ /dev/null @@ -1,35 +0,0 @@ -@import controllers.linking.routes - -@(project: String, task: String) - -@widgets.dialog(title = "Remove Reference Links", submitLabel = "Delete") { - - - - - -
    - - - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/widgets/linkButtons.scala.html b/silk-workbench/silk-workbench-rules/app/views/widgets/linkButtons.scala.html deleted file mode 100644 index 563001dac8..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/widgets/linkButtons.scala.html +++ /dev/null @@ -1,33 +0,0 @@ -@import controllers.rules.routes.Assets -@import java.net.URLEncoder -@import models.linking.EvalLink -@import models.linking.EvalLink._ - -@(link: EvalLink, - rateButtons: Boolean) - -@if(rateButtons) { -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -} else { - Remove link -} - -@encode(link: EvalLink) = {'@link.hashCode', '@URLEncoder.encode(link.source, "UTF-8")', '@URLEncoder.encode(link.target, "UTF-8")'} - -@id(prefix: String = "") = @{ prefix + link.hashCode } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-rules/app/views/widgets/linkingReport.scala.html b/silk-workbench/silk-workbench-rules/app/views/widgets/linkingReport.scala.html deleted file mode 100644 index 6c139b6ef2..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/widgets/linkingReport.scala.html +++ /dev/null @@ -1,23 +0,0 @@ -@import org.silkframework.rule.execution.LinkingStatistics - -@(statistics: LinkingStatistics, linkCount: Int) - -
    -
    - Linking Statistics -
    - - - - - - - - - - - - - -
    Number of source entities:@statistics.entityCount.source
    Number of target entities:@statistics.entityCount.target
    Number of links:@linkCount
    -
    diff --git a/silk-workbench/silk-workbench-rules/app/views/widgets/linksTable.scala.html b/silk-workbench/silk-workbench-rules/app/views/widgets/linksTable.scala.html deleted file mode 100644 index 1b79c8e19d..0000000000 --- a/silk-workbench/silk-workbench-rules/app/views/widgets/linksTable.scala.html +++ /dev/null @@ -1,298 +0,0 @@ -@import controllers.rules.routes.Assets -@import models.linking.EvalLink._ -@import models.linking._ -@import org.silkframework.entity.Entity -@import org.silkframework.entity.paths.UntypedPath -@import org.silkframework.rule.LinkSpec -@import org.silkframework.rule.evaluation._ -@import org.silkframework.rule.execution.LinkingStatistics -@import org.silkframework.runtime.activity.UserContext -@import org.silkframework.util.DPair -@import org.silkframework.workspace.{Project, ProjectTask} -@import java.util.UUID -@import org.silkframework.workbench.Context - -@(project: Project, - task: ProjectTask[LinkSpec], - links: Seq[EvalLink], - linkingStatistics: Option[LinkingStatistics], - linkResolvers: DPair[LinkResolver], - sorting: LinkSorter, - filter: String, - page: Int, - showStatus: Boolean, showDetails: Boolean, showEntities: Boolean, rateButtons: Boolean)(implicit userContext: UserContext) - -@render(getPageLinks()) -@for(statistics <- linkingStatistics) { - @linkingReport(statistics, links.size) -} - -@getPageLinks() = @{ - val pageSize = 100 - val filteredLinks = LinkFilter(links, filter.stripPrefix("filter:")) - val sortedLinks = sorting(filteredLinks) - val pageLinks = sortedLinks.view(page * pageSize, (page + 1) * pageSize).toSeq - pageLinks -} - -@render(pageLinks: Seq[EvalLink]) = { - - -
    - -

    -

    - - - @for((link, index) <- pageLinks.zipWithIndex) { - @renderLink(link, index) - } -
    -

    - -
    - - - -
    -} - -@sortableHeader(ascendingSorter: LinkSorter, descendingSorter: LinkSorter)(content: Html) = { - - @content - {@Assets.at("img/sort-descending.png")} - case _ => {@Assets.at("img/sort.png")} - }"/> - -} - -@renderLink(link: EvalLink, counter: Int) = { - -} - -@renderStatus(linkType: EvalLink.LinkType, correct: EvalLink.Correctness) = { - @linkType match { - case Positive if correct == Correct => {
    correct
    } - case Positive if correct == Incorrect => {
    incorrect
    } - case Negative if correct == Correct => {
    correct
    } - case Negative if correct == Incorrect => {
    incorrect
    } - case Generated if correct == Correct => {
    correct
    } - case Generated if correct == Incorrect => {
    wrong
    } - case _ => {
    unknown
    } - } -} - -@renderButtons(link: EvalLink) = { - @widgets.linkButtons(link, rateButtons) -} - -@renderEntities(entities: DPair[Entity]) = { -
      - @renderEntity(entities.source, "source") - @renderEntity(entities.target, "target") -
    -} - -@renderEntity(entity: Entity, divClassPrefix: String) = { -
  • - - @project.config.prefixes.shorten(entity.uri) - -
      - @for(typedPath <- entity.schema.typedPaths; - path = typedPath.toUntypedPath) { - @renderValues(path, entity.evaluate(path), divClassPrefix) - } -
    -
  • -} - -@renderValues(path: UntypedPath, values: Seq[String], divClassPrefix: String) = { -
  • - @path.serialize()(project.config.prefixes) - @values.take(10).map(v => {project.config.prefixes.shorten(v)}) - @if(values.size > 10) {...} else {} -
  • -} - -@renderDetails(details: Option[Confidence]) = { @details match { - case Some(similarity) => { -
      - @renderSimilarity(similarity) -
    - } - case None => {No details} -}} - -@renderSimilarity(similarity: Confidence) = { @similarity match { - case AggregatorConfidence(value, aggregation, children) => { -
  • - Aggregation:@aggregation.aggregator.pluginSpec.id (@aggregation.id) - @renderConfidence(value) -
      - @children.map(renderSimilarity) -
    -
  • - } - case ComparisonConfidence(value, comparison, input1, input2) => { -
  • - Comparison:@comparison.metric.pluginSpec.id (@comparison.id) - @renderConfidence(value) -
      - @renderValue(input1, "source") - @renderValue(input2, "target") -
    -
  • - } - case SimpleConfidence(value) => { -
  • Link Specification is empty
  • - } -}} - -@renderValue(value: Value, divClassPrefix: String) = { @value match { - case TransformedValue(transform, values, children, error) => { -
  • - - Transform: @transform.transformer.pluginSpec.id (@transform.id) - @values.map(v => {v}) - @renderError(value.formattedErrorMessage) - -
      - @children.map(v => renderValue(v, divClassPrefix)) -
    -
  • - } - case InputValue(input, values, error) => { -
  • - - Input: @input.path.serialize()(project.config.prefixes) (@input.id) - @for(v <- values) { - @convertToLinkIfDetected(v) - } - @renderError(value.formattedErrorMessage) - -
  • - } -}} - -@convertToLinkIfDetected(valueString: String) = { - @if(valueString.startsWith("http://") || valueString.startsWith("https://")) { - @valueString - } else { - @valueString - } -} - -@generateEntityLink(entityUri: String, linkResolver: LinkResolver) = { - @linkResolver(entityUri) match { - case Some(link) => { - - @project.config.prefixes.shorten(entityUri) - - } - case None => { - @project.config.prefixes.shorten(entityUri) - } - } -} - -@renderConfidence(value: Option[Double]) = { @value match { - case Some(v) => { -
    -
    @{"%.1f".format((v) * 100)}%
    -
    - } - case None => {} -}} - -@renderError(error: Option[String], id: String = UUID.randomUUID.toString) = { - @for(e <- error) { - - - - } -} - -@id(link: EvalLink, prefix: String = "") = @{ - prefix + link.hashCode -} diff --git a/silk-workbench/silk-workbench-rules/conf/linking.routes b/silk-workbench/silk-workbench-rules/conf/linking.routes index fb4e5e6e37..8be0c455bb 100644 --- a/silk-workbench/silk-workbench-rules/conf/linking.routes +++ b/silk-workbench/silk-workbench-rules/conf/linking.routes @@ -1,25 +1,3 @@ -# Linkage Rule Editor -GET /:project/:task/editor controllers.linking.LinkingEditor.editor(project: String, task: String) -GET /:project/:task/editor/widgets/paths controllers.linking.LinkingEditor.paths(project: String, task: String, groupPaths: Boolean ?= true) -GET /:project/:task/editor/widgets/score controllers.linking.LinkingEditor.score(project: String, task: String) - -# Evaluate -GET /:project/:task/evaluate controllers.linking.EvaluateLinkingController.generateLinks(project: String, task: String) -GET /:project/:task/evaluate/links/:sorting/:filter/:page controllers.linking.EvaluateLinkingController.links(project: String, task: String, sorting: String, filter: String, page: Int) -GET /:project/:task/evaluate/linksStream controllers.linking.EvaluateLinkingController.linksWebsocket(project: String, task: String) - -# Execute -GET /:project/:task/execute controllers.linking.ExecuteLinkingController.execute(project: String, task: String) -GET /:project/:task/execute/report controllers.linking.ExecuteLinkingController.executionReport(project: String, task: String) - -# Reference Links -GET /:project/:task/referenceLinks controllers.linking.ReferenceLinksManager.referenceLinksView(project: String, task: String) -GET /:project/:task/referenceLinks/addLinkDialog controllers.linking.ReferenceLinksManager.addLinkDialog(project: String, task: String) -GET /:project/:task/referenceLinks/importDialog controllers.linking.ReferenceLinksManager.importDialog(project: String, task: String) -GET /:project/:task/referenceLinks/removeLinksDialog controllers.linking.ReferenceLinksManager.removeLinksDialog(project: String, task: String) -GET /:project/:task/referenceLinks/:linkType/:sorting/:filter/:page controllers.linking.ReferenceLinksManager.referenceLinks(project: String, task: String, linkType: String, sorting: String, filter: String, page: Int) - - # API GET /tasks/:project/:task controllers.linking.LinkingTaskApi.getLinkingTask(project: String, task: String, withLabels: Boolean ?= false, langPref: String ?= "en") POST /tasks/:project/:task controllers.linking.LinkingTaskApi.pushLinkingTask(project: String, task: String, createOnly: Boolean = true) diff --git a/silk-workbench/silk-workbench-rules/conf/transform.routes b/silk-workbench/silk-workbench-rules/conf/transform.routes index edf6126c28..9dcca5a74e 100644 --- a/silk-workbench/silk-workbench-rules/conf/transform.routes +++ b/silk-workbench/silk-workbench-rules/conf/transform.routes @@ -1,20 +1,3 @@ -# Transformation Editor -GET /:project/:task/editor controllers.transform.TransformEditor.start(project: String, task: String, rule = "") -GET /:project/:task/editor/rule/:rule controllers.transform.TransformEditor.start(project: String, task: String, rule: String) -GET /:project/:task/editor/:rule controllers.transform.TransformEditor.editor(project: String, task: String, rule: String) -GET /:project/:task/editor/widgets/property controllers.transform.TransformEditor.propertyDetails(project: String, task: String, property: String) -GET /:project/:task/editor/widgets/paths controllers.transform.TransformEditor.paths(project: String, task: String) -GET /:project/:task/editor/rule/:rule/widgets/paths controllers.transform.TransformEditor.rulePaths(project: String, task: String, rule: String, groupPaths: Boolean ?= true) -GET /:project/:task/editor/widgets/score controllers.transform.TransformEditor.score(project: String, task: String) - -# Evaluate Transformation -GET /:project/:task/evaluate controllers.transform.EvaluateTransform.evaluate(project: String, task: String, rule: Option[String] ?= None, offset: Int ?= 0, limit: Int ?= 100) -GET /:project/:task/evaluate/generatedEntities controllers.transform.EvaluateTransform.generatedEntities(project: String, task: String, rule: Option[String] ?= None, offset: Int ?= 0, limit: Int ?= 100) - -# Execute Transformation -GET /:project/:task/execute controllers.transform.ExecuteTransformTab.execute(project: String, task: String) -GET /:project/:task/execute/report controllers.transform.ExecuteTransformTab.executionReport(project: String, task: String) - # API GET /tasks/:project/:task controllers.transform.TransformTaskApi.getTransformTask(project: String, task: String) PUT /tasks/:project/:task controllers.transform.TransformTaskApi.putTransformTask(project: String, task: String, createOnly: Boolean = false) diff --git a/silk-workbench/silk-workbench-workflow/app/controllers/workflow/Dialogs.scala b/silk-workbench/silk-workbench-workflow/app/controllers/workflow/Dialogs.scala deleted file mode 100644 index 9d9ddf4c71..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/controllers/workflow/Dialogs.scala +++ /dev/null @@ -1,14 +0,0 @@ -package controllers.workflow - -import controllers.core.UserContextActions -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -class Dialogs @Inject() () extends InjectedController with UserContextActions { - - def workflowTaskDialog(project: String): Action[AnyContent] = UserContextAction { implicit userContext => - Ok(views.html.workflow.workflowTaskDialog(project, "")) - } - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workflow/app/controllers/workflow/WorkflowEditorController.scala b/silk-workbench/silk-workbench-workflow/app/controllers/workflow/WorkflowEditorController.scala deleted file mode 100644 index 32864eef86..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/controllers/workflow/WorkflowEditorController.scala +++ /dev/null @@ -1,37 +0,0 @@ -package controllers.workflow - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import models.workflow.WorkflowConfig -import org.silkframework.workbench.Context -import org.silkframework.workbench.workspace.WorkbenchAccessMonitor -import org.silkframework.workspace.WorkspaceFactory -import org.silkframework.workspace.activity.workflow.Workflow -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -/** View endpoints for the workflow editor */ -class WorkflowEditorController @Inject() (implicit accessMonitor: WorkbenchAccessMonitor, workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - - def activityControl(projectId: String, taskId: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val project = WorkspaceFactory().workspace.project(projectId) - val task = project.anyTask(taskId) - val activity = task.activity(WorkflowConfig.executorName) - Ok(views.html.workflow.workflowControl(activity, showButtons = true, insideIFrame = true)) - } - - def reports(project: String, task: String): Action[AnyContent] = reportImpl(project, task, None) - - def report(project: String, task: String, report: String): Action[AnyContent] = reportImpl(project, task, Some(report)) - - def workflowNodeReport(project: String, task: String, nodeId: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[Workflow](project, task, request.path) - Ok(views.html.workflow.workflowNodeExecutionReport(context, nodeId)) - } - - private def reportImpl(project: String, task: String, report: Option[String]): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[Workflow](project, task, request.path) - Ok(views.html.workflow.executionReport(context, report)) - } -} diff --git a/silk-workbench/silk-workbench-workflow/app/views/workflow/executionReport.scala.html b/silk-workbench/silk-workbench-workflow/app/views/workflow/executionReport.scala.html deleted file mode 100644 index 347c02422b..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/views/workflow/executionReport.scala.html +++ /dev/null @@ -1,31 +0,0 @@ - -@import org.silkframework.workspace.activity.workflow.Workflow -@import org.silkframework.workbench.Context -@import org.silkframework.runtime.activity.UserContext -@import controllers.core.routes.{Assets => CoreAssets} - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[Workflow], report: Option[String])(implicit request: RequestHeader, userContext: UserContext, workspaceReact: WorkspaceReact) - -@header = { -} - -@content = { -
    - - @coreLinks.mainJs() - - -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar = null)(content) diff --git a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowControl.scala.html b/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowControl.scala.html deleted file mode 100644 index 43edb11c5c..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowControl.scala.html +++ /dev/null @@ -1,9 +0,0 @@ -@import org.silkframework.workspace.activity.TaskActivity -@import views.html.workspace.activity.taskActivityControl - -@import config.WorkbenchConfig.WorkspaceReact -@(activity: TaskActivity[_, _], showButtons: Boolean = false, insideIFrame: Boolean = false)(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@frame { } { - @taskActivityControl(activity, showButtons, insideIFrame) -} diff --git a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowNodeExecutionReport.scala.html b/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowNodeExecutionReport.scala.html deleted file mode 100644 index 8a19db7f26..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowNodeExecutionReport.scala.html +++ /dev/null @@ -1,34 +0,0 @@ - -@import org.silkframework.workspace.activity.workflow.Workflow -@import org.silkframework.workbench.Context -@import org.silkframework.runtime.activity.UserContext -@import controllers.core.routes.{Assets => CoreAssets} - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[Workflow], nodeId: String)(implicit request: RequestHeader, userContext: UserContext, workspaceReact: WorkspaceReact) - -@header = { - -} - -@content = { -
    - - @coreLinks.mainJs() - - -} - -@frame(header)(content) diff --git a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowTaskDialog.scala.html b/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowTaskDialog.scala.html deleted file mode 100644 index b27a0f6680..0000000000 --- a/silk-workbench/silk-workbench-workflow/app/views/workflow/workflowTaskDialog.scala.html +++ /dev/null @@ -1,49 +0,0 @@ -@import org.silkframework.runtime.activity.UserContext -@(project: String, task: String)(implicit userContext: UserContext) - -@import org.silkframework.workspace.WorkspaceFactory -@import org.silkframework.workspace.activity.workflow.Workflow - -@workflowTask = @{ WorkspaceFactory().workspace.project(project).tasks[Workflow].find(_.id == task) } - -@widgets.dialog(title = "Workflow Task") { - @if(task.isEmpty) { -
    - - -
    - } -} - - \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workflow/conf/workflow.routes b/silk-workbench/silk-workbench-workflow/conf/workflow.routes index cd5f4446a7..865e767fce 100644 --- a/silk-workbench/silk-workbench-workflow/conf/workflow.routes +++ b/silk-workbench/silk-workbench-workflow/conf/workflow.routes @@ -1,10 +1,3 @@ -GET /dialogs/:project/workflowDialog controllers.workflow.Dialogs.workflowTaskDialog(project: String) -GET /activityControl controllers.workflow.WorkflowEditorController.activityControl(projectId, taskId) - -GET /report/:project/:task controllers.workflow.WorkflowEditorController.reports(project: String, task: String) -GET /report/:project/:task/:report controllers.workflow.WorkflowEditorController.report(project: String, task: String, report: String) -GET /workflowNodeReport/:project/:task/:nodeId controllers.workflow.WorkflowEditorController.workflowNodeReport(project: String, task: String, nodeId: String) - GET /workflows/:project controllers.workflow.WorkflowApi.getWorkflows(project: String) POST /workflows/:project controllers.workflow.WorkflowApi.postWorkflow(project: String) diff --git a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/CustomTasks.scala b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/CustomTasks.scala index 95d725c584..3937c39907 100644 --- a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/CustomTasks.scala +++ b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/CustomTasks.scala @@ -46,10 +46,4 @@ class CustomTasks @Inject() () extends InjectedController with UserContextAction WorkspaceFactory().workspace.project(project).removeTask[CustomTask](source) Ok } - - def taskDialog(projectName: String, taskName: String, createDialog: Boolean): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val customTask = if(taskName.isEmpty) None else project.taskOption[CustomTask](taskName).map(p => p.data) - Ok(views.html.workspace.customTask.customTaskDialog(project, taskName, customTask, createDialog)) - } } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetApi.scala b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetApi.scala index 66edb9e4d3..1f1266ead0 100644 --- a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetApi.scala +++ b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetApi.scala @@ -265,86 +265,6 @@ class LegacyDatasetApi @Inject() (implicit workspaceReact: WorkspaceReact) exten NoContent } - def datasetDialog(projectName: String, - datasetName: String, - title: String = "Edit Dataset", - createDialog: Boolean): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val datasetPlugin = if (datasetName.isEmpty) None else project.taskOption[GenericDatasetSpec](datasetName).map(_.data) - Ok(views.html.workspace.dataset.datasetDialog(project, datasetName, datasetPlugin, title, createDialog)) - } - - def datasetDialogAutoConfigured(projectName: String, datasetName: String, pluginId: String): Action[AnyContent] = RequestUserContextAction { request => implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val createDialog = project.taskOption[DatasetSpec[Dataset]](datasetName).isEmpty - val dialogTitle = if(createDialog) "Create Dataset" else "Edit Dataset" - implicit val context: PluginContext = PluginContext.fromProject(project) - val datasetParams = request.queryString.view.mapValues(_.head).toMap - val datasetPlugin = Dataset.apply(pluginId, ParameterValues.fromStringMap(datasetParams)) - datasetPlugin match { - case ds: DatasetPluginAutoConfigurable[_] => - Ok(views.html.workspace.dataset.datasetDialog(project, datasetName, Some(DatasetSpec(ds.autoConfigured)), title = dialogTitle, createDialog = createDialog)) - case _ => - ErrorResult(BadUserInputException("This dataset type does not support auto-configuration.")) - } - } - - def dataset(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - context.task.data match { - case dataset: GenericDatasetSpec => - if (dataset.plugin.isInstanceOf[RdfDataset]) { - Redirect(routes.DatasetController.sparql(project, task)) - } else { - Redirect(routes.DatasetController.table(project, task)) - } - } - } - - def table(project: String, task: String, maxEntities: Int): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - val source = context.task.data.source - implicit val pluginContext: PluginContext = PluginContext.fromProject(context.project) - implicit val prefixes: Prefixes = pluginContext.prefixes - - val firstTypes = source.retrieveTypes().head._1 - val paths = source.retrievePaths(firstTypes).toIndexedSeq - val entityDesc = EntitySchema(firstTypes, paths) - val entities = source.retrieve(entityDesc).entities.use(_.take(maxEntities).toList) - - Ok(views.html.workspace.dataset.table(context, paths.map(_.toUntypedPath), entities)) - } - - def sparql(project: String, task: String, query: String = ""): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - - context.task.data.plugin match { - case rdf: RdfDataset => - val sparqlEndpoint = rdf.sparqlEndpoint - var queryResults: Option[SparqlResults] = None - if (!query.isEmpty) { - queryResults = Some(sparqlEndpoint.select(query)) - } - Ok(views.html.workspace.dataset.sparql(context, sparqlEndpoint, query, queryResults)) - case _ => - ErrorResult(BadUserInputException("This is not an RDF-Dataset.")) - } - } - - /** Get types of a dataset including the search string */ - @deprecated(message = "getDatasetTypes should be used instead.") - def types(project: String, task: String, search: String = "", limit: Option[Int] = None): Action[AnyContent] = RequestUserContextAction { request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - implicit val prefixes: Prefixes = context.project.config.prefixes - - val typesFull = context.task.activity[TypesCache].value().types - val typesResolved = typesFull.map(t => new Uri(t).serialize) - val filteredTypes = typesResolved.filter(_.contains(search)) - val limitedTypes = limit.map(l => filteredTypes.take(l)).getOrElse(filteredTypes) - - Ok(JsArray(limitedTypes.map(JsString))) - } - /** Get all types of the dataset */ @Operation( summary = "Dataset types", diff --git a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetController.scala b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetController.scala deleted file mode 100644 index ec4e8c97e5..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/DatasetController.scala +++ /dev/null @@ -1,88 +0,0 @@ -package controllers.workspace - -import config.WorkbenchConfig.WorkspaceReact -import controllers.core.UserContextActions -import controllers.core.util.ControllerUtilsTrait -import org.silkframework.config.Prefixes -import org.silkframework.dataset.DatasetSpec.GenericDatasetSpec -import org.silkframework.dataset.rdf.{RdfDataset, SparqlResults} -import org.silkframework.dataset.{Dataset, DatasetPluginAutoConfigurable, DatasetSpec} -import org.silkframework.entity.EntitySchema -import org.silkframework.runtime.plugin.{ParameterValues, PluginContext} -import org.silkframework.runtime.validation.BadUserInputException -import org.silkframework.workbench.Context -import org.silkframework.workbench.utils.ErrorResult -import org.silkframework.workspace.WorkspaceFactory -import play.api.mvc.{Action, AnyContent, InjectedController} - -import javax.inject.Inject - -class DatasetController @Inject() (implicit workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions with ControllerUtilsTrait { - - def datasetDialog(projectName: String, - datasetName: String, - title: String = "Edit Dataset", - createDialog: Boolean): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val datasetPlugin = if (datasetName.isEmpty) None else project.taskOption[GenericDatasetSpec](datasetName).map(_.data) - Ok(views.html.workspace.dataset.datasetDialog(project, datasetName, datasetPlugin, title, createDialog)) - } - - def datasetDialogAutoConfigured(projectName: String, datasetName: String, pluginId: String): Action[AnyContent] = RequestUserContextAction { request => implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val createDialog = project.taskOption[DatasetSpec[Dataset]](datasetName).isEmpty - val dialogTitle = if(createDialog) "Create Dataset" else "Edit Dataset" - implicit val context: PluginContext = PluginContext.fromProject(project) - val datasetParams = request.queryString.view.mapValues(_.head).toMap - val datasetPlugin = Dataset.apply(pluginId, ParameterValues.fromStringMap(datasetParams)) - datasetPlugin match { - case ds: DatasetPluginAutoConfigurable[_] => - Ok(views.html.workspace.dataset.datasetDialog(project, datasetName, Some(DatasetSpec(ds.autoConfigured)), title = dialogTitle, createDialog = createDialog)) - case _ => - ErrorResult(BadUserInputException("This dataset type does not support auto-configuration.")) - } - } - - def dataset(project: String, task: String): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - context.task.data match { - case dataset: GenericDatasetSpec => - if (dataset.plugin.isInstanceOf[RdfDataset]) { - Redirect(routes.DatasetController.sparql(project, task)) - } else { - Redirect(routes.DatasetController.table(project, task)) - } - } - } - - def table(project: String, task: String, maxEntities: Int): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - val source = context.task.data.source - implicit val pluginContext: PluginContext = PluginContext.fromProject(context.project) - implicit val prefixes: Prefixes = pluginContext.prefixes - - val firstTypes = source.retrieveTypes().head._1 - val paths = source.retrievePaths(firstTypes).toIndexedSeq - val entityDesc = EntitySchema(firstTypes, paths) - val entities = source.retrieve(entityDesc).entities.use(_.take(maxEntities).toList) - - Ok(views.html.workspace.dataset.table(context, paths.map(_.toUntypedPath), entities)) - } - - def sparql(project: String, task: String, query: String = ""): Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - val context = Context.get[GenericDatasetSpec](project, task, request.path) - - context.task.data.plugin match { - case rdf: RdfDataset => - val sparqlEndpoint = rdf.sparqlEndpoint - var queryResults: Option[SparqlResults] = None - if (!query.isEmpty) { - queryResults = Some(sparqlEndpoint.select(query)) - } - Ok(views.html.workspace.dataset.sparql(context, sparqlEndpoint, query, queryResults)) - case _ => - ErrorResult(BadUserInputException("This is not an RDF-Dataset.")) - } - } - -} diff --git a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/WorkspaceController.scala b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/WorkspaceController.scala index aeb825febb..6885b42527 100644 --- a/silk-workbench/silk-workbench-workspace/app/controllers/workspace/WorkspaceController.scala +++ b/silk-workbench/silk-workbench-workspace/app/controllers/workspace/WorkspaceController.scala @@ -4,8 +4,8 @@ import config.WorkbenchConfig import config.WorkbenchConfig.WorkspaceReact import controllers.core.UserContextActions import org.silkframework.util.Identifier +import org.silkframework.workspace.WorkspaceFactory import org.silkframework.workspace.xml.XmlZipProjectMarshaling -import org.silkframework.workspace.{PrefixRegistry, WorkspaceFactory} import play.api.mvc.{Action, AnyContent, InjectedController} import java.nio.file.{Files, StandardCopyOption} @@ -13,58 +13,6 @@ import javax.inject.Inject class WorkspaceController @Inject() (implicit workspaceReact: WorkspaceReact) extends InjectedController with UserContextActions { - def index: Action[AnyContent] = Action { implicit request => - Ok(views.html.workspace.workspace()) - } - - def tree: Action[AnyContent] = UserContextAction { implicit userContext => - Ok(views.html.workspace.workspaceTree(WorkspaceFactory().workspace)) - } - - def activities: Action[AnyContent] = RequestUserContextAction { implicit request => implicit userContext => - Ok(views.html.workspace.activities()) - } - - def newProjectDialog(): Action[AnyContent] = Action { - Ok(views.html.workspace.newProjectDialog()) - } - - def importProjectDialog(): Action[AnyContent] = Action { - Ok(views.html.workspace.importProjectDialog()) - } - - def removeProjectDialog(project: String): Action[AnyContent] = UserContextAction { implicit userContext => - Ok(views.html.workspace.removeProjectDialog(project, WorkspaceFactory().workspace.repository.sharedResources)) - } - - def removeTaskDialog(projectName: String, taskName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.anyTask(taskName) - val dependentTasks = task.findDependentTasks(recursive = false).map(project.anyTask(_).label()).toSeq - - Ok(views.html.workspace.removeTaskDialog(projectName, taskName, task.label(), dependentTasks)) - } - - def removeResourceDialog(name: String, path: String): Action[AnyContent] = Action { - Ok(views.html.workspace.removeResourceDialog(name, path)) - } - - def importLinkSpecDialog(project: String): Action[AnyContent] = Action { - Ok(views.html.workspace.importLinkSpecDialog(project)) - } - - def prefixDialog(project: String): Action[AnyContent] = UserContextAction { implicit userContext => - val prefixes = WorkspaceFactory().workspace.project(project).config.prefixes - - Ok(views.html.workspace.prefixDialog(project, prefixes, PrefixRegistry.all)) - } - - def resourcesDialog(project: String): Action[AnyContent] = UserContextAction { implicit userContext => - val resourceManager = WorkspaceFactory().workspace.project(project).resources - - Ok(views.html.workspace.resourcesDialog(project, resourceManager)) - } - def importExample(project: String): Action[AnyContent] = UserContextAction { implicit userContext => val workspace = WorkspaceFactory().workspace @@ -84,30 +32,4 @@ class WorkspaceController @Inject() (implicit workspaceReact: WorkspaceReact) ex Ok } - - def executeProjectDialog(projectName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - Ok(views.html.workspace.executeProjectDialog(project)) - } - - def projectActivityConfigDialog(projectName: String, activityName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val activity = project.activity(activityName) - Ok(views.html.workspace.activity.projectActivityConfigDialog(activity)) - } - - def taskActivityConfigDialog(projectName: String, taskName: String, activityName: String): Action[AnyContent] = UserContextAction { implicit userContext => - val project = WorkspaceFactory().workspace.project(projectName) - val task = project.anyTask(taskName) - val activity = task.activity(activityName) - Ok(views.html.workspace.activity.taskActivityConfigDialog(activity)) - } - - def cloneProjectDialog(project: String) = Action { - Ok(views.html.workspace.cloneProjectDialog(project)) - } - - def cloneTaskDialog(project: String, task: String) = Action { - Ok(views.html.workspace.cloneTaskDialog(project, task)) - } } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activities.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activities.scala.html deleted file mode 100644 index 84b312e8ab..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activities.scala.html +++ /dev/null @@ -1,241 +0,0 @@ -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.workspace.routes.{ActivityApi, Assets, WorkspaceController} -@import org.silkframework.config.TaskSpec -@import org.silkframework.workspace.activity.CachedActivity -@import org.silkframework.runtime.activity.HasValue -@import org.silkframework.workspace.activity.{CachedActivity, ProjectActivity, TaskActivity} -@import org.silkframework.workspace.{Project, ProjectTask, WorkspaceFactory, Workspace} -@import org.silkframework.runtime.activity.UserContext -@import config.WorkbenchConfig - -@** - * Overview page of all activities and their status - *@ -@import org.silkframework.workspace.activity.GlobalWorkspaceActivity -@import config.WorkbenchConfig.WorkspaceReact -@()(implicit session: play.api.mvc.Session, userContext: UserContext, request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - - - - - -} - -@toolbar = { -} - -@content = { -
    -
    - @workspaceActivities(WorkspaceFactory().workspace) -
    -
    - -
    -} - -@globalWorkspaceActivities(workspace: Workspace) = { -
      - @for(activity <- workspace.activities) { - @globalWorkspaceActivityStatus(activity) - } -
    -} - -@workspaceActivities(workspace: Workspace) = { -
    - @globalWorkspaceActivities(workspace) -
      - @for(project <- workspace.userProjects) { - @projectActivities(project) - } -
    -
    -} - -@projectActivities(project: Project) = { -
  • - @project.id -
      - Project Activities - @for(activity <- project.activities) { - @projectActivityStatus(project, activity) - } -
    -
      - @for(task <- project.allTasks) { - @taskActivities(project, task) - } -
    -
  • -} - -@taskActivities(project: Project, task: ProjectTask[_ <: TaskSpec]) = { -
  • - @task.label() -
      - @for(activity <- task.activities) { - @taskActivityStatus(project, task, activity) - } -
    -
  • -} - -@globalWorkspaceActivityStatus(activity: GlobalWorkspaceActivity[_ <: HasValue]) = { -
  • - @activity.label -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
  • -} - -@projectActivityStatus(project: Project, activity: ProjectActivity[_ <: HasValue]) = { -
  • - @activity.label -
    -
    - -
    -
    - -
    -
    - -
    - @if(activity.defaultConfig.nonEmpty) { -
    - -
    - } -
  • -} - -@taskActivityStatus(project: Project, task: ProjectTask[_ <: TaskSpec], activity: TaskActivity[_, _]) = { -
  • - @activity.label -
    -
    - -
    -
    - -
    -
    - -
    -
    - @if(activity.defaultConfig.nonEmpty) { - - } -
    -
    - @if(!activity.isUnitValueType) { - - } -
    -
    - @if(classOf[CachedActivity[_]].isAssignableFrom(activity.control.underlying.getClass)) { - - } -
    -
  • -} - -@id(project: String, task: String, activity: String) = @{ - "progress_" + project + "_" + task + "_" + helper.urlEncode(activity) -} - -@main(None, "activities")(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/activityControl.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/activityControl.scala.html deleted file mode 100644 index e6932643b0..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/activityControl.scala.html +++ /dev/null @@ -1,208 +0,0 @@ -@import controllers.core.routes.Assets -@import controllers.workspace.routes.ActivityApi -@import controllers.workspace.routes.WorkspaceController -@import org.silkframework.workspace.activity.WorkspaceActivity -@import config.WorkbenchConfig - -@(project: String, - task: Option[String], - activity: WorkspaceActivity[_], - showProgressBar: Boolean, - showStartButton: Boolean, - showRestartButton: Boolean, - showConfigButton: Boolean, - insideIFrame: Boolean)(implicit request: RequestHeader) - -
    - - @if(showProgressBar) { -
    -
    - -
    -
    -
    - } - - @if(showStartButton) { - - -
    - Start @activity.label -
    - -
    - Stop @activity.label -
    -
    - } - - @if(showRestartButton) { - - -
    - Reset @activity.label to its initial value and restart. -
    -
    - } - - @if(showConfigButton && task.isDefined) { - - -
    - Start @activity.label after configuring parameters. -
    -
    - } - - @if(showConfigButton && task.isEmpty) { - - -
    - Start @activity.label after configuring parameters. -
    -
    - } - -
    - - - -@id(prefix: String) = @{ - prefix + project + "_" + task.getOrElse("") + "_" + helper.urlEncode(activity.name) -} diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/autoReload.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/autoReload.scala.html deleted file mode 100644 index 17fdfa7ebd..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/autoReload.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@import controllers.workspace.routes.ActivityApi -@import org.silkframework.workbench.Context -@import config.WorkbenchConfig - -@(context: Context[_], contentPath: String, activityId: String)(implicit request: RequestHeader) - -@id() = @{ - "autoreload-" + activityId -} - - - -
    diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityConfigDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityConfigDialog.scala.html deleted file mode 100644 index 8ca73a45a0..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityConfigDialog.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@import controllers.workspace.routes -@import org.silkframework.runtime.plugin.{AnyPlugin, ClassPluginDescription} -@import org.silkframework.workspace.activity.ProjectActivity -@import org.silkframework.runtime.activity.HasValue -@import scala.language.existentials -@import org.silkframework.runtime.activity.UserContext - -@(activity: ProjectActivity[_ <: HasValue])(implicit userContext: UserContext) - -@widgets.pluginDialog( - activity.project, - name = activity.name, - plugins = ClassPluginDescription(activity.factory.getClass) :: Nil, - currentObj = Some(activity.factory.asInstanceOf[AnyPlugin]), - resources = Nil) { - - -} diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityControl.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityControl.scala.html deleted file mode 100644 index da1b72ab40..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/projectActivityControl.scala.html +++ /dev/null @@ -1,17 +0,0 @@ -@import org.silkframework.workspace.activity.ProjectActivity -@import org.silkframework.workspace.activity.CachedActivity -@import org.silkframework.runtime.activity.HasValue -@import scala.language.existentials - -@(activity: ProjectActivity[_ <: HasValue], showButtons: Boolean = false, insideIFrame: Boolean = false)(implicit request: RequestHeader) - -@activityControl( - project = activity.project.id, - task = None, - activity = activity, - showProgressBar = true, - showStartButton = showButtons, - showRestartButton = showButtons && classOf[CachedActivity[_]].isAssignableFrom(activity.control.underlying.getClass), - showConfigButton = showButtons && activity.defaultConfig.nonEmpty, - insideIFrame = insideIFrame -) diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityConfigDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityConfigDialog.scala.html deleted file mode 100644 index 6caf3f0a66..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityConfigDialog.scala.html +++ /dev/null @@ -1,35 +0,0 @@ -@import controllers.workspace.routes -@import org.silkframework.runtime.plugin.{AnyPlugin, ClassPluginDescription} -@import org.silkframework.workspace.activity.TaskActivity -@import org.silkframework.runtime.activity.UserContext - -@import scala.language.existentials - -@(activity: TaskActivity[_, _])(implicit userContext: UserContext) - -@widgets.pluginDialog( - activity.project, - name = activity.name, - title = "Start activity", - submitLabel = "start", - plugins = ClassPluginDescription(activity.factory.getClass) :: Nil, - currentObj = Some(activity.factory.asInstanceOf[AnyPlugin]), - resources = Nil) { - - -} diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityControl.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityControl.scala.html deleted file mode 100644 index 0102e30abb..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/activity/taskActivityControl.scala.html +++ /dev/null @@ -1,15 +0,0 @@ -@import org.silkframework.workspace.activity.TaskActivity -@import org.silkframework.workspace.activity.CachedActivity - -@(activity: TaskActivity[_, _], showButtons: Boolean = false, insideIFrame: Boolean = false)(implicit request: RequestHeader) - -@activityControl( - project = activity.task.project.id, - task = Some(activity.task.id), - activity = activity, - showProgressBar = true, - showStartButton = showButtons, - showRestartButton = showButtons && classOf[CachedActivity[_]].isAssignableFrom(activity.control.underlying.getClass), - showConfigButton = showButtons && activity.defaultConfig.nonEmpty, - insideIFrame = insideIFrame -) \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneProjectDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneProjectDialog.scala.html deleted file mode 100644 index c03298795f..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneProjectDialog.scala.html +++ /dev/null @@ -1,34 +0,0 @@ -@(project: String) - -@widgets.dialog(title = "Clone Project " + project, submitLabel = "Clone") { -
    - - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneTaskDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneTaskDialog.scala.html deleted file mode 100644 index 2ad137f29b..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/cloneTaskDialog.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@(project: String, task: String) - -@widgets.dialog(title = "Clone " + task, submitLabel = "Clone") { -
    - - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/customTask/customTaskDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/customTask/customTaskDialog.scala.html deleted file mode 100644 index 87ac707437..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/customTask/customTaskDialog.scala.html +++ /dev/null @@ -1,36 +0,0 @@ -@import org.silkframework.config.CustomTask -@import org.silkframework.runtime.plugin.PluginRegistry -@import org.silkframework.workspace.Project -@import org.silkframework.runtime.activity.UserContext - -@(project: Project, taskName: String, taskPlugin: Option[CustomTask], createDialog: Boolean)(implicit userContext: UserContext) - -@widgets.pluginDialog( - project, - name = taskName, - plugins = PluginRegistry.availablePlugins[CustomTask], - currentObj = taskPlugin, - resources = project.resources.list, - createDialog = createDialog) { - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/datasetDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/datasetDialog.scala.html deleted file mode 100644 index 27a6963fae..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/datasetDialog.scala.html +++ /dev/null @@ -1,55 +0,0 @@ -@import org.silkframework.dataset.Dataset -@import org.silkframework.workspace.Project -@import org.silkframework.dataset.DatasetSpec.GenericDatasetSpec -@import org.silkframework.runtime.activity.UserContext - -@(project: Project, datasetName: String, dataset: Option[GenericDatasetSpec], title: String = "Edit Dataset", createDialog: Boolean = false)(implicit userContext: UserContext) - -@widgets.pluginDialog( - project, - name = datasetName, - plugins = Dataset.availablePlugins, - currentObj = dataset.map(_.plugin), - resources = project.resources.listRecursive, - title = title, - submitLabel = "Save", - secondaryLabel = "Autoconfigure", - createDialog = createDialog) { - -
    - - -
    - When reading data from the dataset, the specified attribute will be used to get the URIs of the entities. When writing to a dataset, the specified attribute will be automatically added to the schema as well as the generated entity URIs will be added as values for each entity." -
    -
    - - - } \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/sparql.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/sparql.scala.html deleted file mode 100644 index 91f9242d7f..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/sparql.scala.html +++ /dev/null @@ -1,71 +0,0 @@ -@import org.silkframework.workbench.Context - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[org.silkframework.dataset.DatasetSpec.GenericDatasetSpec], - endpoint: org.silkframework.dataset.rdf.SparqlEndpoint, - query: String, - queryResults: Option[org.silkframework.dataset.rdf.SparqlResults])(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - -} - -@toolbar = { - -} - -@content = { -
    -
    - @queryCard -
    -
    - @resultTable -
    -
    -} - -@queryCard = { -
    -
    -
    -
    - -
    - -
    -
    -
    -} - -@resultTable = { - - - - @for(results <- queryResults.toList; - variable <- results.variables) { - - - - @for(results <- queryResults.toList; bindings <- results.bindings) { - - @for((variable, node) <- bindings) { - - } - -
    @variable - } -
    @node.value - } -
    -} - -@defaultQuery = {@for((prefix, namespace) <- context.project.config.prefixes.prefixMap) {PREFIX @prefix: <@namespace> -} -SELECT * WHERE { - ?s ?p ?o -} -LIMIT 20 -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/table.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/table.scala.html deleted file mode 100644 index 0ca4679db0..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/dataset/table.scala.html +++ /dev/null @@ -1,43 +0,0 @@ -@import org.silkframework.entity.Entity -@import org.silkframework.dataset.DatasetSpec.GenericDatasetSpec -@import org.silkframework.entity.paths.UntypedPath -@import org.silkframework.workbench.Context - -@import config.WorkbenchConfig.WorkspaceReact -@(context: Context[GenericDatasetSpec], paths: IndexedSeq[UntypedPath], entities: Seq[Entity])(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - -} - -@toolbar = { -} - -@content = { - - - - @for(path <- paths) { - - - - @for(entity <- entities) { - - @for(path <- paths) { - - } - -
    @path.toString - } -
    @entity.evaluate(path) - } -
    -} - -@main(Some(context), titleLabel = context.task.label())(header)(toolbar)(content) \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/executeProjectDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/executeProjectDialog.scala.html deleted file mode 100644 index 6371a9a6c0..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/executeProjectDialog.scala.html +++ /dev/null @@ -1,21 +0,0 @@ -@import org.silkframework.runtime.plugin.PluginRegistry -@import org.silkframework.workspace.activity.ProjectExecutor -@import org.silkframework.workspace.Project -@import controllers.workspace.routes -@import org.silkframework.runtime.activity.UserContext - -@(project: Project)(implicit userContext: UserContext) - -@widgets.pluginDialog(project, - name = project.id, - plugins = PluginRegistry.availablePlugins[ProjectExecutor], - currentObj = None, - resources = Nil) { - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/importLinkSpecDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/importLinkSpecDialog.scala.html deleted file mode 100644 index e735c1bd35..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/importLinkSpecDialog.scala.html +++ /dev/null @@ -1,39 +0,0 @@ -@(project: String) - -@widgets.dialog(title = "Import Link Specification", submitLabel = "Import", width = 500) { -
    - -
    - - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/importProjectDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/importProjectDialog.scala.html deleted file mode 100644 index 2f73cc9c70..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/importProjectDialog.scala.html +++ /dev/null @@ -1,45 +0,0 @@ -@() - -@widgets.dialog(title = "Import Project", submitLabel = "Import") { - -
    - - -
    -
    - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/newProjectDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/newProjectDialog.scala.html deleted file mode 100644 index 6aa18e615a..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/newProjectDialog.scala.html +++ /dev/null @@ -1,29 +0,0 @@ -@() - -@widgets.dialog(title = "New Project", submitLabel = "Create") { -
    - - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog.scala.html deleted file mode 100644 index 6f559ff075..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog.scala.html +++ /dev/null @@ -1,88 +0,0 @@ -@(project: String, - prefixes: org.silkframework.config.Prefixes, - knownPrefixes: org.silkframework.config.Prefixes) - -@widgets.dialog(title = "Edit Prefixes", submitLabel = "Save Prefixes") { -
    - - - - - - - - - @for(prefix <- prefixes) { - - - - - } - - - - - -
    Prefix
    -
    - -
    -
    - -
    - -
    -
    - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog_improved.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog_improved.scala.html deleted file mode 100644 index 88c32ec8d1..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/prefixDialog_improved.scala.html +++ /dev/null @@ -1,97 +0,0 @@ -@(project: String, - prefixes: org.silkframework.config.Prefixes, - knownPrefixes: org.silkframework.config.Prefixes) - -@widgets.dialog(title = "Edit Prefixes", submitLabel = "Save Prefixes") { - - - - - - - - - - @for(prefix <- prefixes) { - - - - } - - - - - - -
    PrefixURI
    -
    - -
    -
    -
    - -
    -
    - -
    - -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeProjectDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/removeProjectDialog.scala.html deleted file mode 100644 index e23e6ede20..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeProjectDialog.scala.html +++ /dev/null @@ -1,22 +0,0 @@ -@(project: String, sharedResources: Boolean) - -@widgets.dialog(title = "Delete Project", submitLabel = "Yes, delete it") { - -

    - @if(sharedResources) { - Delete project @project? Note that resources will not be deleted because they are shared across projects. - } else { - Delete project @project including all resources? - } -

    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeResourceDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/removeResourceDialog.scala.html deleted file mode 100644 index 63980ceec5..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeResourceDialog.scala.html +++ /dev/null @@ -1,28 +0,0 @@ -@(name: String, path: String) - -@widgets.dialog(title = "Delete", submitLabel = "Yes, delete it") { - -

    - Delete resource: @name -

    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeTaskDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/removeTaskDialog.scala.html deleted file mode 100644 index 359161a71f..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/removeTaskDialog.scala.html +++ /dev/null @@ -1,37 +0,0 @@ -@(project: String, task: String, taskLabel: String, dependentTaskLabels: Seq[String]) - -@if(dependentTaskLabels.isEmpty) { - - @widgets.dialog(title = "Delete task", submitLabel = "Yes, delete it") { -

    - Delete task: @taskLabel -

    - - - } - -} else { - - @widgets.dialog(title = "Cannot delete task", submitLabel = "Ok") { -

    - Cannot delete task @taskLabel, because the following tasks depend on it: -

      - @for(dependentTaskLabel <- dependentTaskLabels) { -
    • @dependentTaskLabel
    • - } -
    -

    - - - } - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/resourcesDialog.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/resourcesDialog.scala.html deleted file mode 100644 index 7f075eec1a..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/resourcesDialog.scala.html +++ /dev/null @@ -1,254 +0,0 @@ -@(project: String, resourceLoader: org.silkframework.runtime.resource.ResourceLoader) - -@import controllers.workspace.routes.Assets - -@widgets.dialog(title = "Manage Resources", width = 500) { -
    - -
    - @for((resource, index) <- resourceLoader.listRecursive.zipWithIndex) { -
    - @resource - - file_download - clear -
    -
    - @resource -
    -
    - modified: @resourceLoader.get(resource, mustExist = false).modificationTime.map(_.toString).getOrElse("") -
    - } -
    - -
    -
    -
    - Upload Local -
    - Upload an input resource from a local file. -
    - Import from URL -
    - Import an input resource from an external URL. -
    - Define Output -
    - Create a new output resource. -
    -
    - -
    -
    - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    - -
    - -
    -

    - - Delete resource? -

    -
    - - -} \ No newline at end of file diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/workspace.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/workspace.scala.html deleted file mode 100644 index 3667622bb4..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/workspace.scala.html +++ /dev/null @@ -1,39 +0,0 @@ -@import controllers.core.routes.{Assets => CoreAssets} -@import controllers.workspace.routes.Assets - -@import config.WorkbenchConfig.WorkspaceReact -@()(implicit request: RequestHeader, workspaceReact: WorkspaceReact) - -@header = { - - - - -} - -@toolbar = { -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -} - -@content = { -
    -
    -
    -
    - -
    -
    -
    -} - -@main(None, "workspace")(header)(toolbar)(content) diff --git a/silk-workbench/silk-workbench-workspace/app/views/workspace/workspaceTree.scala.html b/silk-workbench/silk-workbench-workspace/app/views/workspace/workspaceTree.scala.html deleted file mode 100644 index a0d0da6b0d..0000000000 --- a/silk-workbench/silk-workbench-workspace/app/views/workspace/workspaceTree.scala.html +++ /dev/null @@ -1,194 +0,0 @@ -@import controllers.workspace.routes.Assets -@import org.silkframework.runtime.plugin.PluginRegistry -@import org.silkframework.workbench.WorkbenchPlugin.{TaskActions, TaskType} -@import org.silkframework.workbench.WorkbenchPlugins -@import org.silkframework.workspace.activity.ProjectExecutor -@import org.silkframework.workspace.{Project, Workspace} -@import org.silkframework.runtime.activity.UserContext - -@import org.silkframework.runtime.plugin.PluginContext -@(workspace: Workspace)(implicit userContext: UserContext) - - - -
    - - -
    - -@* Either a link opening a new tab if linkUrl is set or a button executing the onClick JavaScript *@ -@button(title: String, tooltip: String, icon: String, onClick: String, linkUrl: String = "") = { - @if(linkUrl.trim.isEmpty) { -
    - - @title -
    - } else { - - } -} - -@project(project: Project) = { -
  • - @project.config.metaData.formattedLabel(project.id, maxLength = 100) - @button("Prefixes", "Edit prefixes", "wrench-screwdriver.png", s"editPrefixes('${project.id}')") - @button("Resources", "Manage resources", "wrench.png", s"editResources('${project.id}')") - @button("Link Spec", "Import link specification", "document--plus.png", s"importLinkSpec('${project.id}')") - @button("Export", "Export project", "document-export.png", s"exportProject('${project.id}')") - @if(PluginRegistry.availablePlugins[ProjectExecutor].nonEmpty) { - @button("Execute", "Execute project", "document-export.png", s"executeProject('${project.id}')") - } - @button("Clone", "Clone project", "clone.png", s"cloneProject('${project.id}')") - @button("Remove", "Remove project", "cross.png", s"deleteProjectConfirm('${project.id}')") -
      - @for((taskType, taskActions) <- WorkbenchPlugins.byType(project)) { - @taskTypeNode(project, taskType, taskActions) - } -
    -
  • -} - -@projectIcon(project: Project) = @{ - if(project.loadingErrors.isEmpty) - "img/project.png" - else - "img/project-error.png" -} - -@taskTypeNode(project: Project, taskType: TaskType, taskActions: Seq[TaskActions]) = { -
  • - @{taskType.typeName}s - @for(path <- taskType.createDialog(project.id)) { - @button("Add", "Add " + taskType.typeName, "plus.png", s"workspaceDialog('$path')") - } -
      - @for(actions <- taskActions.sortBy(_.task.label()).reverse) { - @task(project, taskType, actions) - } -
    -
  • -} - -@task(project: Project, taskType: TaskType, actions: TaskActions) = { -
  • - @actions.task.label() - @for(path <- actions.propertiesDialog) { - @button("Properties", "Edit task properties", "wrench.png", s"workspaceDialog('$path')") - } - @for(path <- actions.openPath(None, None)) { - @button("Open", "Open task", "document--pencil.png", s"window.location = '${config.baseUrl}/$path'", config.baseUrl + "/" + path) - } - @button("Clone", "Clone task", "clone.png", s"cloneTask('${project.id}', '${actions.task.id}')") - @button("Remove", "Remove task", "cross.png", s"deleteTaskConfirm('${project.id}', '${actions.task.id}')") -
      - @for((key, value) <- actions.task.metaDataFields() ++ actions.task.data.parameters(PluginContext.fromProject(project)).toStringMap(PluginContext.empty) if !value.isEmpty) { -
    • - @key: @value -
    • - } -
    -
  • -} - -
    -
      - @for(p <- workspace.userProjects) { - @project(p) - } -
    -
    diff --git a/silk-workbench/silk-workbench-workspace/conf/workspace.routes b/silk-workbench/silk-workbench-workspace/conf/workspace.routes index f49369372c..f6395ff84e 100644 --- a/silk-workbench/silk-workbench-workspace/conf/workspace.routes +++ b/silk-workbench/silk-workbench-workspace/conf/workspace.routes @@ -2,39 +2,12 @@ # Workspace ############################################################################################################################################ -GET / controllers.workspace.WorkspaceController.index() -GET /tree controllers.workspace.WorkspaceController.tree() -GET /allActivities controllers.workspace.WorkspaceController.activities() - -GET /dialogs/newproject controllers.workspace.WorkspaceController.newProjectDialog() -GET /dialogs/importproject controllers.workspace.WorkspaceController.importProjectDialog() -GET /dialogs/removeproject/:project controllers.workspace.WorkspaceController.removeProjectDialog(project: String) -GET /dialogs/removetask/:project/:task controllers.workspace.WorkspaceController.removeTaskDialog(project: String, task: String) -GET /dialogs/removeresource/:name controllers.workspace.WorkspaceController.removeResourceDialog(name: String, path: String) -GET /dialogs/importlinkspec/:project controllers.workspace.WorkspaceController.importLinkSpecDialog(project: String) -GET /dialogs/prefixes/:project controllers.workspace.WorkspaceController.prefixDialog(project: String) -GET /dialogs/resources/:project controllers.workspace.WorkspaceController.resourcesDialog(project: String) -GET /dialogs/executeProject/:project controllers.workspace.WorkspaceController.executeProjectDialog(project: String) -GET /dialogs/cloneProject controllers.workspace.WorkspaceController.cloneProjectDialog(project) -GET /dialogs/cloneTask controllers.workspace.WorkspaceController.cloneTaskDialog(project, task) -GET /dialogs/activityConfig/:project/:activity controllers.workspace.WorkspaceController.projectActivityConfigDialog(project: String, activity: String) -GET /dialogs/activityConfig/:project/:task/:activity controllers.workspace.WorkspaceController.taskActivityConfigDialog(project: String, task: String, activity: String) POST /:project/importExample controllers.workspace.WorkspaceController.importExample(project: String) ############################################################################################################################################ # Datasets ############################################################################################################################################ -# Dialogs -GET /dialogs/newDataset/:project controllers.workspace.DatasetController.datasetDialog(project: String, task = "", title = "Create Dataset", createDialog: Boolean = true) -GET /dialogs/editDataset/:project/:task controllers.workspace.DatasetController.datasetDialog(project: String, task: String, title = "Edit Dataset", createDialog: Boolean = false) -GET /dialogs/editDatasetAutoConfigured/:project/:task/:pluginId controllers.workspace.DatasetController.datasetDialogAutoConfigured(project, task, pluginId) - -# Tabs -GET /datasets/:project/:task/dataset controllers.workspace.DatasetController.dataset(project, task) -GET /datasets/:project/:task/table controllers.workspace.DatasetController.table(project, task, maxEntities: Int ?= 20) -GET /datasets/:project/:task/sparql controllers.workspace.DatasetController.sparql(project, task, query ?= "") -GET /datasets/:project/:task/types controllers.workspace.LegacyDatasetApi.types(project, task, search, limit: Option[Int] ?= None) # API PUT /projects/:project/datasets/:name controllers.workspace.LegacyDatasetApi.putDataset(project: String, name: String, autoConfigure: Boolean ?= false) @@ -51,10 +24,6 @@ POST /projects/:project/datasets/:name/mappingCoverage/values # CustomTasks ############################################################################################################################################ -# Dialogs -GET /customTasks/newTaskDialog/:project controllers.workspace.CustomTasks.taskDialog(project: String, task = "", createDialog: Boolean = true) -GET /customTasks/editTaskDialog/:project/:task controllers.workspace.CustomTasks.taskDialog(project: String, task: String, createDialog: Boolean = false) - # API GET /projects/:project/customTasks/:name controllers.workspace.CustomTasks.getTask(project: String, name: String) POST /projects/:project/customTasks/:name controllers.workspace.CustomTasks.pushTask(project: String, name: String, createOnly: Boolean = true) diff --git a/workspace/config/jest/config.js b/workspace/config/jest/config.js index 27e40db9d5..41a7732f92 100644 --- a/workspace/config/jest/config.js +++ b/workspace/config/jest/config.js @@ -2,7 +2,7 @@ module.exports = { rootDir: "./../../", - testEnvironment: "jsdom", + testEnvironment: "jest-fixed-jsdom", testEnvironmentOptions: { url: "http://localhost/", globalsCleanup: "on", @@ -20,12 +20,12 @@ module.exports = { "/test/**/*(*.)@(spec|test).{js,jsx,ts,tsx}", ], transform: { - "^.+\\.(js|jsx|ts|tsx)$": "babel-jest", + "^.+\\.(js|jsx|ts|tsx|mjs|cjs)$": "babel-jest", "^.+\\.css$": "/config/jest/cssTransform.js", "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "/config/jest/fileTransform.js", }, transformIgnorePatterns: [ - "[/\\\\]node_modules[/\\\\](?!react-markdown|vfile|unist-util-stringify-position|).+\\.(js|jsx|ts|tsx)$", + "[/\\\\]node_modules[/\\\\](?!react-markdown|vfile|unist-util-stringify-position|@reduxjs/toolkit|).+\\.(js|jsx|ts|tsx|mjs|cjs)$", "^.+\\.module\\.(css|sass|scss)$", ], moduleNameMapper: { @@ -33,6 +33,7 @@ module.exports = { "^react-markdown$": "/../node_modules/react-markdown", "^@eccenca/gui-elements$": "/../node_modules/@eccenca/gui-elements", "^@eccenca/gui-elements/(.*)$": "/../node_modules/@eccenca/gui-elements/$1", + "^@reduxjs/toolkit$": "/../node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs", "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy", "@ducks(.*)$": "/src/app/store/ducks/$1", }, diff --git a/workspace/config/jest/subproject.js b/workspace/config/jest/subproject.js index ffaaae671f..eae44f038b 100644 --- a/workspace/config/jest/subproject.js +++ b/workspace/config/jest/subproject.js @@ -8,5 +8,6 @@ module.exports = { "^react-markdown$": "/../../node_modules/react-markdown", "^@eccenca/gui-elements$": "/../../node_modules/@eccenca/gui-elements", "^@eccenca/gui-elements/(.*)$": "/../../node_modules/@eccenca/gui-elements/$1", + "^@reduxjs/toolkit$": "/../../node_modules/@reduxjs/toolkit/dist/cjs/redux-toolkit.development.cjs", }, }; diff --git a/workspace/package.json b/workspace/package.json index 7755cf1112..5fc589c910 100644 --- a/workspace/package.json +++ b/workspace/package.json @@ -16,7 +16,7 @@ "watch": "node --openssl-legacy-provider --max_old_space_size=2048 scripts/build-di.dev.js --watch", "build-di-dev": "node --openssl-legacy-provider scripts/build-di.dev.js", "build-di-prod": "node --openssl-legacy-provider --max_old_space_size=2048 scripts/build-di.prod.js", - "test": "node scripts/test.js", + "test": "DEBUG=true node scripts/test.js", "test-ci": "export CI=true && node scripts/test.js --coverage --reporters=\"default\" --reporters=\"jest-junit\" --no-colors --ci --silent", "sync-trans": "sync-i18n --files 'src/locales/manual/*.json' --primary en --languages de --space 4 -- --check", "i18n-parser": "node scripts/i18next-scanner.js", @@ -25,10 +25,14 @@ "lint:js": "eslint --ignore-path .gitignore '{src,test}/**/*.{js,jsx,ts,tsx}'" }, "dependencies": { + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@dnd-kit/modifiers": "^9.0.0", "@eccenca/gui-elements": "^25.0.0", "@eccenca/superagent": "^1.4.1", "@mavrin/remark-typograf": "^2.2.0", - "@reduxjs/toolkit": "^1.9.7", + "@reduxjs/toolkit": "^2.11.1", "@uppy/core": "1.17.0", "@uppy/react": "1.11.10", "@uppy/xhr-upload": "1.7.5", @@ -39,7 +43,6 @@ "dexie": "^3.2.3", "ecc-messagebus": "^3.6.0", "ecc-utils": "^1.4.0", - "gui-elements-deprecated": "npm:@eccenca/gui-elements@^5.1.1", "history": "^4.7.2", "i18next": "^25.1.3", "i18next-browser-languagedetector": "^8.1.0", @@ -48,16 +51,15 @@ "qs": "^6.14.0", "query-string": "^6.13.7", "react-app-polyfill": "^1.0.6", - "react-beautiful-dnd": "^13.1.1", "react-flow-renderer": "9.7.4", "react-helmet": "^6.0.0", - "react-hook-form": "^5.1.3", + "react-hook-form": "^7.71.1", "react-i18next": "^11.18.6", - "react-redux": "^7.2.9", + "react-redux": "^9.2.0", "react-router": "^5.3.4", "react-router-dom": "^5.3.4", "react-sparklines": "^1.7.0", - "redux": "^4.2.1", + "redux": "^5.0.1", "redux-logger": "^3.0.6", "store": "^2.0.12" }, @@ -118,12 +120,12 @@ "@cyclonedx/webpack-plugin": "^2.0.2", "@svgr/webpack": "^8.1.0", "@testing-library/jest-dom": "^6.6.4", - "@testing-library/react": "^12.1.5", + "@testing-library/react": "^14.3.1", "@testing-library/user-event": "^14.6.1", "@types/jest": "^30.0.0", "@types/ramda": "^0.26.6", - "@types/react": "^17.0.85", - "@types/react-dom": "^17.0.8", + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", "@types/react-redux": "^7.1.34", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", @@ -132,11 +134,11 @@ "@typescript-eslint/parser": "^6.21.0", "@welldone-software/why-did-you-render": "^4.0.5", "babel-eslint": "10.1.0", - "babel-jest": "^26.6.3", + "babel-jest": "^30.2.0", "babel-loader": "^8.4.1", "babel-plugin-named-asset-import": "^0.3.8", "babel-preset-react-app": "^10.1.0", - "browserslist": "^4.24.5", + "browserslist": "^4.28.1", "case-sensitive-paths-webpack-plugin": "^2.4.0", "cross-env": "^7.0.3", "css-loader": "^5.2.7", @@ -151,6 +153,7 @@ "eslint-plugin-react": "^7.20.6", "eslint-plugin-react-hooks": "^4.0.8", "eslint-plugin-simple-import-sort": "^10.0.0", + "@eslint/compat": "^1.4.1", "file-loader": "^5.1.0", "fork-ts-checker-webpack-plugin": "^6.5.3", "fs-extra": "^8.1.0", @@ -202,6 +205,7 @@ "resolutions": { "**/minimist": "^1.2.8", "sanitize.css": "12.0.1", - "**/url-parse": "1.5.9" + "**/url-parse": "1.5.9", + "react-redux": "^9.1.2" } } diff --git a/workspace/scripts/test.js b/workspace/scripts/test.js index 9ccd3dba61..484a63f440 100644 --- a/workspace/scripts/test.js +++ b/workspace/scripts/test.js @@ -54,5 +54,5 @@ if ( if (argv.indexOf("--no-watch") !== -1) { argv = argv.filter((arg) => arg !== "--no-watch"); } - +argv.push("--detectOpenHandles", "--logHeapUsage") jest.run(argv); diff --git a/workspace/src/app/App.tsx b/workspace/src/app/App.tsx index a19abd0be1..897feb0556 100644 --- a/workspace/src/app/App.tsx +++ b/workspace/src/app/App.tsx @@ -1,10 +1,10 @@ import React, { useEffect } from "react"; import { ConnectedRouter } from "connected-react-router"; -import { useDispatch } from "react-redux"; +import { useDispatch, ReactReduxContext } from "react-redux"; import { commonOp } from "@ducks/common"; import RouterOutlet from "./RouterOutlet"; -import { getHistory } from "./store/configureStore"; +import { AppDispatch, getHistory } from "./store/configureStore"; import { IRouteProps } from "./appRoutes"; import { GlobalContextsWrapper } from "./GlobalContextsWrapper"; @@ -14,13 +14,12 @@ interface IProps { } export default function App({ externalRoutes, routes }: IProps) { - const dispatch = useDispatch(); + const dispatch = useDispatch(); useEffect(() => { dispatch(commonOp.fetchCommonSettingsAsync()); dispatch(commonOp.fetchExportTypesAsync()); }, [commonOp]); - return ( diff --git a/workspace/src/app/hooks/useCopyButton.tsx b/workspace/src/app/hooks/useCopyButton.tsx index f796e88fd1..193a8a7a79 100644 --- a/workspace/src/app/hooks/useCopyButton.tsx +++ b/workspace/src/app/hooks/useCopyButton.tsx @@ -19,7 +19,7 @@ interface ICopyData { const COPY_RESET_TIMEOUT = 1000; -const useCopyButton = (data: Array, resetTimeout = COPY_RESET_TIMEOUT): JSX.Element[] => { +const useCopyButton = (data: Array, resetTimeout = COPY_RESET_TIMEOUT): React.JSX.Element[] => { const [activeButton, setActiveButton] = React.useState(); const { registerError } = useErrorHandler(); const [t] = useTranslation(); diff --git a/workspace/src/app/hooks/useErrorHandler.tsx b/workspace/src/app/hooks/useErrorHandler.tsx index ca23836115..19b6302e5f 100644 --- a/workspace/src/app/hooks/useErrorHandler.tsx +++ b/workspace/src/app/hooks/useErrorHandler.tsx @@ -19,7 +19,7 @@ export type ErrorHandlerRegisterFuncType = ( errorMessage: string, cause: DIErrorTypes | null, options?: ErrorHandlerOptions, -) => JSX.Element | null; +) => React.JSX.Element | null; interface ErrorHandlerOptions { /** The notification instance where the error should be displayed. If this is set, the @@ -40,7 +40,7 @@ type ErrorHandlerRegisterShortFuncType = ( /** The error cause. */ cause: DIErrorTypes | null, options?: ErrorHandlerOptions, -) => JSX.Element | null; +) => React.JSX.Element | null; interface ErrorHandlerDict { registerError: ErrorHandlerRegisterFuncType; diff --git a/workspace/src/app/hooks/useSelectFirstResult.ts b/workspace/src/app/hooks/useSelectFirstResult.ts index c871c2b835..d2c1b2e2cd 100644 --- a/workspace/src/app/hooks/useSelectFirstResult.ts +++ b/workspace/src/app/hooks/useSelectFirstResult.ts @@ -5,9 +5,10 @@ import { IPageLabels } from "@ducks/router/operations"; import { workspaceOp, workspaceSel } from "@ducks/workspace"; import { DATA_TYPES } from "../constants"; import { batch, useDispatch, useSelector } from "react-redux"; +import { AppDispatch } from "store/configureStore"; export const useSelectFirstResult = () => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const data = useSelector(workspaceSel.resultsSelector); const dataArrayRef = React.useRef(data); const enabled = React.useRef(true); diff --git a/workspace/src/app/services/errorLogger.ts b/workspace/src/app/services/errorLogger.ts index 2b86866742..6d4b7a3c48 100644 --- a/workspace/src/app/services/errorLogger.ts +++ b/workspace/src/app/services/errorLogger.ts @@ -161,7 +161,7 @@ const logError = (error: FetchError | Error, reactErrorInfo?: ErrorInfo): boolea } else if (error instanceof Error) { const { name, message, stack } = error; const newStack = reactErrorInfo ? reactErrorInfo.componentStack : stack; - err = generateDefaultError(name, message, newStack); + err = generateDefaultError(name, message, newStack || undefined); } else { err = generateDefaultError("Uncaught Error type received ", error); } diff --git a/workspace/src/app/store/configureStore.ts b/workspace/src/app/store/configureStore.ts index 94211a22cf..05b8101e74 100644 --- a/workspace/src/app/store/configureStore.ts +++ b/workspace/src/app/store/configureStore.ts @@ -1,5 +1,5 @@ import rootReducer from "./reducers"; -import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit"; +import { configureStore } from "@reduxjs/toolkit"; import { createBrowserHistory } from "history"; import { routerMiddleware } from "connected-react-router"; import { createLogger } from "redux-logger"; @@ -16,12 +16,7 @@ export const getHistory = () => history; export default function configStore(options: any = {}) { const enhancers: any[] = []; - const middleware = [ - ...getDefaultMiddleware({ - serializableCheck: false, - }), - routerMiddleware(getHistory()), - ]; + const middleware = [routerMiddleware(getHistory())]; if (isDevelopment) { const { enableStoreDevUtils, monitorPerformance, logReduxActions, logUselessRenders } = options; // Enable redux development actions, e.g. reset store @@ -59,10 +54,13 @@ export default function configStore(options: any = {}) { store = configureStore({ reducer: rootReducer(getHistory()), - middleware, + middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }).concat(middleware), devTools: isDevelopment, - enhancers, + enhancers: (defaultEnhancers) => defaultEnhancers().concat(enhancers), }); return store; } + +export type AppDispatch = typeof store.dispatch; +export type RootState = ReturnType; diff --git a/workspace/src/app/store/ducks/common/commonSlice.ts b/workspace/src/app/store/ducks/common/commonSlice.ts index ff13c5bbf7..f334cbceda 100644 --- a/workspace/src/app/store/ducks/common/commonSlice.ts +++ b/workspace/src/app/store/ducks/common/commonSlice.ts @@ -1,4 +1,4 @@ -import { createAction, createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { ActionReducerMapBuilder, createAction, createSlice, PayloadAction, WritableDraft } from "@reduxjs/toolkit"; import { initialCommonState } from "./initialState"; import { LOCATION_CHANGE } from "connected-react-router"; import appRoutes from "../../../appRoutes"; @@ -13,6 +13,7 @@ import { IInitFrontend, IProjectTaskUpdatePayload, IArtefactModal, + ICommonState, } from "@ducks/common/typings"; import { setStoredLang } from "../../../../language"; @@ -20,37 +21,35 @@ import { setStoredLang } from "../../../../language"; * @override connect-react-router location change action * set projectId and taskId on location change */ -const getExtraReducers = () => { +const getExtraReducers = (builder: ActionReducerMapBuilder>) => { const routerChange = createAction(LOCATION_CHANGE); - return { - [routerChange.toString()]: (state) => { - const { location } = getHistory(); - const updatedState = { - ...state, - }; - - let match; - for (let route of appRoutes) { - match = matchPath<{ taskId?: string; projectId?: string }>(location.pathname, { - path: getFullRoutePath(route.path), - exact: true, - }); + builder.addCase(routerChange.toString(), (state) => { + const { location } = getHistory(); + const updatedState = { + ...state, + }; + + let match; + for (let route of appRoutes) { + match = matchPath<{ taskId?: string; projectId?: string }>(location.pathname, { + path: getFullRoutePath(route.path), + exact: true, + }); - if (match) { - updatedState.currentProjectId = match.params.projectId || null; - updatedState.currentTaskId = match.params.taskId || null; - break; - } + if (match) { + updatedState.currentProjectId = match.params.projectId || null; + updatedState.currentTaskId = match.params.taskId || null; + break; } + } - if (!match) { - updatedState.currentTaskId = null; - updatedState.currentProjectId = null; - } + if (!match) { + updatedState.currentTaskId = undefined; + updatedState.currentProjectId = undefined; + } - return updatedState; - }, - }; + return updatedState; + }); }; export const commonSlice = createSlice({ @@ -164,7 +163,7 @@ export const commonSlice = createSlice({ createNewTask: ( state, - action: PayloadAction> + action: PayloadAction>, ) => { const { newTaskPreConfiguration, selectedDType } = action.payload; state.artefactModal.newTaskPreConfiguration = newTaskPreConfiguration; @@ -185,5 +184,5 @@ export const commonSlice = createSlice({ state.artefactModal.info = action.payload; }, }, - extraReducers: getExtraReducers(), + extraReducers: (builder) => getExtraReducers(builder), }); diff --git a/workspace/src/app/store/ducks/common/operations.ts b/workspace/src/app/store/ducks/common/operations.ts index 63a350b625..f4a1f6f2f8 100644 --- a/workspace/src/app/store/ducks/common/operations.ts +++ b/workspace/src/app/store/ducks/common/operations.ts @@ -54,6 +54,23 @@ const { toggleUserMenuDisplay, } = commonSlice.actions; +let artefactModalLoadingRequests = 0; +let artefactListRequestId = 0; + +const beginArtefactModalLoading = (dispatch) => { + artefactModalLoadingRequests += 1; + if (artefactModalLoadingRequests === 1) { + dispatch(setArtefactLoading(true)); + } +}; + +const endArtefactModalLoading = (dispatch) => { + artefactModalLoadingRequests = Math.max(artefactModalLoadingRequests - 1, 0); + if (artefactModalLoadingRequests === 0) { + dispatch(setArtefactLoading(false)); + } +}; + const fetchCommonSettingsAsync = () => { return async (dispatch) => { try { @@ -123,10 +140,11 @@ const fetchAvailableDTypesAsync = (id?: string) => { const fetchArtefactsListAsync = (filters: any = {}) => { return async (dispatch) => { + const requestId = ++artefactListRequestId; batch(() => { dispatch(fetchArtefactsList()); - dispatch(setArtefactLoading(true)); }); + beginArtefactModalLoading(dispatch); try { const data = await requestArtefactList(filters); @@ -135,11 +153,15 @@ const fetchArtefactsListAsync = (filters: any = {}) => { ...data[key], })); - dispatch(setArtefactsList(result)); + if (requestId === artefactListRequestId) { + dispatch(setArtefactsList(result)); + } } catch (e) { - dispatch(setError(e)); + if (requestId === artefactListRequestId) { + dispatch(setError(e)); + } } finally { - dispatch(setArtefactLoading(false)); + endArtefactModalLoading(dispatch); } }; }; @@ -157,13 +179,13 @@ const getArtefactPropertiesAsync = (artefact: IPluginOverview) => { dispatch(selectArtefact(artefact)); if (!cachedArtefactProperties[artefact.key]) { - dispatch(setArtefactLoading(true)); - - const data = await requestArtefactProperties(artefact.key); - batch(() => { - dispatch(setArtefactLoading(false)); + beginArtefactModalLoading(dispatch); + try { + const data = await requestArtefactProperties(artefact.key); dispatch(setCachedArtefactProperty(data)); - }); + } finally { + endArtefactModalLoading(dispatch); + } } }; }; @@ -186,26 +208,13 @@ const splitParameterAndVariableTemplateParameters = (formData: any, variableTemp }; /** Builds a request object for project/task create call. */ -const buildNestedTaskParameterObject = (formData: Record): TaskParameters => { +const buildStringValuedObject = (formData: Record): TaskParameters => { const returnObject: TaskParameters = Object.create(null); - const nestedParamsFlat = Object.entries(formData).filter(([k, v]) => k.includes(".")); - const directParams = Object.entries(formData).filter(([k, v]) => !k.includes(".")); - // Add direct parameters - directParams.forEach(([paramId, param]) => { - returnObject[paramId] = "" + param; - }); - // Group nested parameters by first parameter ID, create nested value objects - const nestedParamsMap = nestedParamsFlat.reduce((obj, [combinedParamId, param]) => { - const firstDot = combinedParamId.indexOf("."); - const paramId = combinedParamId.substring(0, firstDot); - const nestedParamId = combinedParamId.substring(firstDot + 1); - obj[paramId] = obj[paramId] || {}; - obj[paramId][nestedParamId] = param; - return obj; - }, {}); - // Add nested parameters to result object and call buildTaskObject recursively - Object.entries(nestedParamsMap).forEach(([propName, value]) => { - returnObject[propName] = buildNestedTaskParameterObject(value as Record); + const params = Object.entries(formData); + params.forEach(([paramId, param]) => { + const convertedParam: TaskParameters | string = + typeof param === "object" ? buildStringValuedObject(param) : "" + param; + returnObject[paramId] = convertedParam; }); return returnObject; }; @@ -300,8 +309,8 @@ const fetchCreateTaskAsync = ( restFormData, variableTemplateParameterSet, ); - const parameterData = buildNestedTaskParameterObject(parameters); - const variableTemplateData = buildNestedTaskParameterObject(variableTemplateParameters); + const parameterData = buildStringValuedObject(parameters); + const variableTemplateData = buildStringValuedObject(variableTemplateParameters); const metadata = { label, description, @@ -376,8 +385,8 @@ const fetchUpdateTaskAsync = ( formData, variableTemplateParameterSet, ); - const parameterData = buildNestedTaskParameterObject(parameters); - const variableTemplateData = buildNestedTaskParameterObject(variableTemplateParameters); + const parameterData = buildStringValuedObject(parameters); + const variableTemplateData = buildStringValuedObject(variableTemplateParameters); const payload = { data: { ...dataParameters, @@ -443,10 +452,13 @@ const fetchCreateProjectAsync = ( const resetArtefactModal = (shouldClose: boolean = false) => (dispatch) => { + artefactModalLoadingRequests = 0; + artefactListRequestId += 1; batch(() => { dispatch(selectArtefact(undefined)); dispatch(setModalError({})); dispatch(setModalInfo(undefined)); + dispatch(setArtefactLoading(false)); if (shouldClose) { dispatch(closeArtefactModal()); } @@ -477,7 +489,7 @@ const commonOps = { setSelectedArtefactDType, setModalError, setModalInfo, - buildNestedTaskParameterObject: buildNestedTaskParameterObject, + buildStringValuedObject, fetchCreateTaskAsync, fetchUpdateTaskAsync, fetchCreateProjectAsync, diff --git a/workspace/src/app/store/ducks/common/tests/operations.test.ts b/workspace/src/app/store/ducks/common/tests/operations.test.ts index 3553606cf5..3519a2cd34 100644 --- a/workspace/src/app/store/ducks/common/tests/operations.test.ts +++ b/workspace/src/app/store/ducks/common/tests/operations.test.ts @@ -1,18 +1,26 @@ import commonOps from "../operations"; describe("commonOps", () => { - test("buildTaskObject should construct nested objects from flat objects", () => { + test("buildStringValuedObject should convert all literal values to string values in a nested object", () => { const flatObject = { id: 1, - "source.id": 2, - "source.name": "2", - "target.id": 3, - "target.name": "3", - "source.extra.id": 4, - "source.extra.name": "extra", + root: true, + source: { + id: 2, + name: "2", + extra: { + id: 4, + name: "extra" + } + }, + target: { + id: 3, + name: "3" + } }; const expectedResult = { id: "1", + root: "true", source: { id: "2", name: "2", @@ -26,6 +34,6 @@ describe("commonOps", () => { name: "3", }, }; - expect(commonOps.buildNestedTaskParameterObject(flatObject)).toEqual(expectedResult); + expect(commonOps.buildStringValuedObject(flatObject)).toEqual(expectedResult); }); }); diff --git a/workspace/src/app/store/ducks/common/typings.ts b/workspace/src/app/store/ducks/common/typings.ts index c20a8700b9..fb8aad05af 100644 --- a/workspace/src/app/store/ducks/common/typings.ts +++ b/workspace/src/app/store/ducks/common/typings.ts @@ -1,3 +1,4 @@ +import React from "react"; import { IAutocompleteDefaultResponse, IMetadata, @@ -37,7 +38,7 @@ interface AutoCompletionFrontendExtensions { query: string, modifiers: SuggestFieldItemRendererModifierProps, handleSelectClick: () => any, - ) => string | JSX.Element; + ) => string | React.JSX.Element; } /** Properties for parameter auto-completion. */ diff --git a/workspace/src/app/store/reducers.ts b/workspace/src/app/store/reducers.ts index 682646fe7a..d13f2f1295 100644 --- a/workspace/src/app/store/reducers.ts +++ b/workspace/src/app/store/reducers.ts @@ -3,11 +3,11 @@ import { combineReducers } from "@reduxjs/toolkit"; import workspace from "@ducks/workspace"; import common from "@ducks/common"; import routerReducers from "@ducks/router"; -import { Reducer, Action, CombinedState } from "redux"; +import { Reducer, Action } from "redux"; import { IStore } from "./typings/IStore"; import error from "@ducks/error"; -const reducers = (history): Reducer, Action> => { +const reducers = (history): Reducer => { return combineReducers({ common: common.reducer, workspace, diff --git a/workspace/src/app/utils/dndkitUtils.ts b/workspace/src/app/utils/dndkitUtils.ts new file mode 100644 index 0000000000..b3b75385aa --- /dev/null +++ b/workspace/src/app/utils/dndkitUtils.ts @@ -0,0 +1,49 @@ +/** Contains utility functions for the dnd-kit drag and drop library.*/ + +import {MouseSensor, MouseSensorOptions, SensorDescriptor} from "@dnd-kit/core"; +import {MouseEvent} from "react"; + +/** Blocks DnD event propagation if element has "nodrag" class. Do not use this for allowing clicks. Clicks should be + * fixed by adding the distance activationConstraint to the useSensor function. + * Use this for cases like allowing copying text or input elements. + * */ +const preventDraggingInNoDragElements = (targetElement: HTMLElement ): boolean => { + let cur = targetElement + while (cur) { + if (cur.classList.contains("nodrag")) { + return false; + } + cur = cur.parentElement as HTMLElement; + } + + return true; +} + +/** Mouse sensor that does not drag elements having the "nodrag" class attached to them. */ +class DefaultMouseSensor extends MouseSensor { + static activators = [{ + eventName: 'onMouseDown', + handler: ({ nativeEvent: event }: MouseEvent): boolean => { + if(event.button !== 0) { + // Only allow dragging with left mouse button + return false + } else { + return preventDraggingInNoDragElements(event.target as HTMLElement) + } + } + }] satisfies typeof MouseSensor['activators']; +} + +const defaultMouseSensorOptions: MouseSensorOptions = { + activationConstraint: { + distance: 5, + } +} + +const exportObject = { + preventDraggingInNoDragElements, + DefaultMouseSensor, + defaultMouseSensorOptions +} + +export default exportObject diff --git a/workspace/src/app/utils/uiUtils.tsx b/workspace/src/app/utils/uiUtils.tsx index c5c1b8515e..2164e8906d 100644 --- a/workspace/src/app/utils/uiUtils.tsx +++ b/workspace/src/app/utils/uiUtils.tsx @@ -4,11 +4,11 @@ import React from "react"; /** Wraps an element inside a tooltip when the wrap predicate is true. */ export const wrapTooltip = ( wrapPredicate: boolean, - childTooltip: string | JSX.Element, - child: JSX.Element, + childTooltip: string | React.JSX.Element, + child: React.JSX.Element, position: ContextOverlayProps["placement"] = "bottom-start", - size: "large" | "small" | "medium" = "large" -): JSX.Element => { + size: "large" | "small" | "medium" = "large", +): React.JSX.Element => { if (wrapPredicate) { return ( diff --git a/workspace/src/app/views/layout/Header/ExampleProjectImportMenu.tsx b/workspace/src/app/views/layout/Header/ExampleProjectImportMenu.tsx index 55e4b0c0c0..d1c3305ad1 100644 --- a/workspace/src/app/views/layout/Header/ExampleProjectImportMenu.tsx +++ b/workspace/src/app/views/layout/Header/ExampleProjectImportMenu.tsx @@ -6,11 +6,12 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { routerOp } from "@ducks/router"; import { requestProjectMetadata } from "@ducks/shared/requests"; +import { AppDispatch } from "store/configureStore"; /** Component to load the "movies" example project. */ export const ExampleProjectImportMenu = () => { const { registerError } = useErrorHandler(); - const dispatch = useDispatch(); + const dispatch = useDispatch(); const [t] = useTranslation(); const [exampleProjectLoaded, setExampleProjectLoaded] = React.useState(undefined); const [loading, setLoading] = React.useState(false); diff --git a/workspace/src/app/views/layout/Header/Header.tsx b/workspace/src/app/views/layout/Header/Header.tsx index 83e9682aa7..d67b24464a 100644 --- a/workspace/src/app/views/layout/Header/Header.tsx +++ b/workspace/src/app/views/layout/Header/Header.tsx @@ -37,6 +37,7 @@ import { UserMenuFooterProps } from "../../plugins/plugin.types"; import { ExampleProjectImportMenu } from "./ExampleProjectImportMenu"; import { useKeyboardHeaderShortcuts } from "./useKeyBoardHeaderShortcuts"; import { getFullRoutePath } from "../../../utils/routerUtils"; +import { AppDispatch } from "store/configureStore"; interface IProps { onClickApplicationSidebarExpand: any; @@ -44,7 +45,7 @@ interface IProps { } export function Header({ onClickApplicationSidebarExpand, isApplicationSidebarExpanded }: IProps) { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const location = useLocation(); const locationParams = new URLSearchParams(location.search?.substring(1)); const { hotKeys } = useSelector(commonSel.initialSettingsSelector); diff --git a/workspace/src/app/views/layout/Header/useKeyBoardHeaderShortcuts.ts b/workspace/src/app/views/layout/Header/useKeyBoardHeaderShortcuts.ts index 00ff2d14ef..646ead0ae1 100644 --- a/workspace/src/app/views/layout/Header/useKeyBoardHeaderShortcuts.ts +++ b/workspace/src/app/views/layout/Header/useKeyBoardHeaderShortcuts.ts @@ -9,10 +9,11 @@ import { DATA_TYPES } from "../../../constants"; import { uppercaseFirstChar } from "../../../utils/transformers"; import { useTranslation } from "react-i18next"; import { absoluteProjectPath } from "../../../utils/routerUtils"; +import { AppDispatch } from "store/configureStore"; import { ModalContext } from "@eccenca/gui-elements/src/components/Dialog/ModalContext"; export const useKeyboardHeaderShortcuts = () => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const [t] = useTranslation(); const projectId = useSelector(commonSel.currentProjectIdSelector); const modalContext = React.useContext(ModalContext); diff --git a/workspace/src/app/views/pages/Activities/ActivityList.tsx b/workspace/src/app/views/pages/Activities/ActivityList.tsx index 06ec7dbd9d..cafb41e3d7 100644 --- a/workspace/src/app/views/pages/Activities/ActivityList.tsx +++ b/workspace/src/app/views/pages/Activities/ActivityList.tsx @@ -36,6 +36,7 @@ import { routerOp } from "@ducks/router"; import { batch } from "react-redux"; import { SERVE_PATH } from "../../../constants/path"; import { DIErrorTypes } from "@ducks/error/typings"; +import { AppDispatch } from "store/configureStore"; import { GlobalTableContext } from "../../../GlobalContextsWrapper"; interface IActivity extends ISearchResultsServer { @@ -57,7 +58,7 @@ export const nonStartableActivitiesBlacklist = { }; const ActivityList = () => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const pageSizes = [10, 25, 50, 100]; const { registerError } = useErrorHandler(); const { globalTableSettings } = React.useContext(GlobalTableContext); diff --git a/workspace/src/app/views/pages/Activities/index.tsx b/workspace/src/app/views/pages/Activities/index.tsx index b32d6d3322..9697d5c7a9 100644 --- a/workspace/src/app/views/pages/Activities/index.tsx +++ b/workspace/src/app/views/pages/Activities/index.tsx @@ -30,10 +30,11 @@ import { useHistory, useParams } from "react-router"; import { SERVE_PATH } from "../../../constants/path"; import { ProjectTaskParams } from "views/shared/typings"; import { previewSlice } from "@ducks/workspace/previewSlice"; +import { AppDispatch } from "store/configureStore"; import { GlobalTableContext } from "../../../GlobalContextsWrapper"; const Activities = () => { - const dispatch = useDispatch(); + const dispatch = useDispatch(); const { registerError } = useErrorHandler(); const history = useHistory(); const error = useSelector(workspaceSel.errorSelector); diff --git a/workspace/src/app/views/pages/Activities/tests/ActivitiesList.test.tsx b/workspace/src/app/views/pages/Activities/tests/ActivitiesList.test.tsx index ecb060520f..5bd77441fa 100644 --- a/workspace/src/app/views/pages/Activities/tests/ActivitiesList.test.tsx +++ b/workspace/src/app/views/pages/Activities/tests/ActivitiesList.test.tsx @@ -1,7 +1,7 @@ import React from "react"; import "@testing-library/jest-dom"; import { render as rtlRender } from "@testing-library/react"; -import { configureStore } from "@reduxjs/toolkit"; +import { combineReducers, configureStore } from "@reduxjs/toolkit"; import { createMemoryHistory } from "history"; import { connectRouter, routerMiddleware } from "connected-react-router"; import { Provider } from "react-redux"; @@ -50,13 +50,17 @@ const dummyState = { }, }; +const rootReducer = combineReducers({ + workspace: workspaceReducer, +}); + const render = ( - ui: JSX.Element, + ui: React.JSX.Element, { store = configureStore({ - reducer: { workspace: workspaceReducer, router: connectRouter(history) }, + reducer: rootReducer, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(routerMiddleware(history)), preloadedState: { - middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(routerMiddleware(history)), ...(dummyState as any), }, }), diff --git a/workspace/src/app/views/pages/Linking/config/LinkageRuleConfigModal.tsx b/workspace/src/app/views/pages/Linking/config/LinkageRuleConfigModal.tsx index c86258c2a7..e7a355a846 100644 --- a/workspace/src/app/views/pages/Linking/config/LinkageRuleConfigModal.tsx +++ b/workspace/src/app/views/pages/Linking/config/LinkageRuleConfigModal.tsx @@ -18,7 +18,7 @@ export const LinkageRuleConfigModal = ({ onClose, parameters, submit }: IProps) const [t] = useTranslation(); const [parameterDiff] = useState>(new Map()); const [changed, setChanged] = useState(false); - const [requestError, setRequestError] = useState(undefined); + const [requestError, setRequestError] = useState(undefined); const [errorCount, setErrorCount] = useState(0); const initialParameters = new Map(parameters.map((p) => [p.id, p])); const [errors] = useState(new Map()); diff --git a/workspace/src/app/views/pages/MappingEditor/ExecutionReport/ExecutionReport.tsx b/workspace/src/app/views/pages/MappingEditor/ExecutionReport/ExecutionReport.tsx index 49189ba09e..2d2fa3ae99 100644 --- a/workspace/src/app/views/pages/MappingEditor/ExecutionReport/ExecutionReport.tsx +++ b/workspace/src/app/views/pages/MappingEditor/ExecutionReport/ExecutionReport.tsx @@ -70,7 +70,7 @@ export const ExecutionReport = ({ executionReport, executionMetaData, trackRuleI title = t("ExecutionReport.defaultTitle"); } - let executionMetaDataPairs: JSX.Element[] = []; + let executionMetaDataPairs: React.JSX.Element[] = []; if (executionMetaData != null) { executionMetaDataPairs = executionMetaDataPairs.concat([ @@ -213,7 +213,7 @@ export const ExecutionReport = ({ executionReport, executionMetaData, trackRuleI return ( - + { - this.setState({ - currentRuleId: newRuleId, - }); - }; - - render() { - return ( -
    -
    - -
    -