diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index 6054334e4a6..405c710d07e 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -37,6 +37,8 @@ In the curl command below, replace the placeholder "fabulousFileTool.json" place curl -X POST -H 'Content-type: application/json' http://localhost:8080/api/admin/externalTools --upload-file fabulousFileTool.json +Note that some tools will provide a preview mode, which provides an embedded, simplified view of the tool on the file pages of your installation. This is controlled by the `hasPreviewMode` parameter. + Listing All External Tools in Dataverse +++++++++++++++++++++++++++++++++++++++ @@ -76,10 +78,15 @@ Once you have added an external tool to your installation of Dataverse, you will File Level Explore Tools ++++++++++++++++++++++++ -File level explore tools are specific to the file type (content type or MIME type) of the file. For example, there is a tool for exploring PDF files in the "File Previewers" set of tools. +File level explore tools are specific to the file type (content type or MIME type) of the file. For example, Data Explorer is tool for exploring tabular data files. An "Explore" button will appear (on both the dataset page and the file landing page) for files that match the type that the tool has been built for. When there are multiple explore tools for a filetype, the button becomes a dropdown. +File Level Preview Tools +++++++++++++++++++++++++ + +File level explore tools can be set up to display in preview mode, which is a simplified view of an explore tool designed specifically for embedding in the file page. + File Level Configure Tools ++++++++++++++++++++++++++ diff --git a/doc/sphinx-guides/source/admin/integrations.rst b/doc/sphinx-guides/source/admin/integrations.rst index 2ed8581eb50..5c4ddbff230 100644 --- a/doc/sphinx-guides/source/admin/integrations.rst +++ b/doc/sphinx-guides/source/admin/integrations.rst @@ -90,7 +90,7 @@ Dataverse supports a protocol called OAI-PMH that facilitates harvesting dataset SHARE +++++ -`SHARE `_ is building a free, open, data set about research and scholarly activities across their life cycle. It's possible to add and installation of Dataverse as one of the `sources `_ they include if you contact the SHARE team. +`SHARE `_ is building a free, open, data set about research and scholarly activities across their life cycle. It's possible to add an installation of Dataverse as one of the `sources `_ they include if you contact the SHARE team. Research Data Preservation -------------------------- diff --git a/doc/sphinx-guides/source/api/external-tools.rst b/doc/sphinx-guides/source/api/external-tools.rst index fc5adf00c2b..5e58e68c853 100644 --- a/doc/sphinx-guides/source/api/external-tools.rst +++ b/doc/sphinx-guides/source/api/external-tools.rst @@ -29,7 +29,13 @@ Note: This is the same list that appears in the :doc:`/admin/external-tools` sec How External Tools Are Presented to Users ----------------------------------------- -In short, an external tool appears under an "Explore" or "Configure" button either on a dataset landing page or a file landing page. See also the :ref:`testing-external-tools` section of the Admin Guide for some perspective on how installations of Dataverse will expect to test your tool before announcing it to their users. +An external tool can appear in Dataverse in one of three ways: + +- under an "Explore" or "Configure" button either on a dataset landing page +- under an "Explore" or "Configure" button on a file landing page +- as an embedded preview on the file landing page + +See also the :ref:`testing-external-tools` section of the Admin Guide for some perspective on how installations of Dataverse will expect to test your tool before announcing it to their users. Creating an External Tool Manifest ---------------------------------- @@ -75,6 +81,8 @@ Terminology type Whether the external tool is an **explore** tool or a **configure** tool. Configure tools require an API token because they make changes to data files (files within datasets). Configure tools are currently not supported at the dataset level (no "Configure" button appears in the GUI for datasets). toolUrl The **base URL** of the tool before query parameters are added. + + hasPreviewMode A boolean that indicates whether tool has a preview mode which can be embedded in the File Page. Since this view is designed for embedding within Dataverse, the preview mode for a tool will typically be a view without headers or other options that may be included with a tool that is designed to be launched in a new window. Sometimes, a tool will exist solely to preview files in Dataverse and the preview mode will be the same as the regular view. contentType File level tools operate on a specific **file type** (content type or MIME type such as "application/pdf") and this must be specified. Dataset level tools do not use contentType. diff --git a/doc/sphinx-guides/source/user/dataset-management.rst b/doc/sphinx-guides/source/user/dataset-management.rst index 3cdc9aec954..5edcd29c083 100755 --- a/doc/sphinx-guides/source/user/dataset-management.rst +++ b/doc/sphinx-guides/source/user/dataset-management.rst @@ -69,7 +69,7 @@ If there are multiple upload options available, then you must choose which one t You can upload files to a dataset while first creating that dataset. You can also upload files after creating a dataset by clicking the "Edit" button at the top of the dataset page and from the dropdown list selecting "Files (Upload)" or clicking the "Upload Files" button above the files table in the Files tab. From either option you will be brought to the Upload Files page for that dataset. -Certain file types in Dataverse are supported by additional functionality, which can include downloading in different formats, file-level metadata preservation, file-level data citation with UNFs, and exploration through data visualization and analysis. See the :ref:`File Handling ` section of this page for more information. +Certain file types in Dataverse are supported by additional functionality, which can include downloading in different formats, previews, file-level metadata preservation, file-level data citation with UNFs, and exploration through data visualization and analysis. See the :ref:`File Handling ` section of this page for more information. HTTP Upload @@ -143,8 +143,12 @@ DVUploader is a community-developed tool, and its creation was primarily support File Handling ============= -Certain file types in Dataverse are supported by additional functionality, which can include downloading in different formats, file-level metadata preservation, file-level data citation; and exploration through data visualization and analysis. See the sections below for information about special functionality for specific file types. +Certain file types in Dataverse are supported by additional functionality, which can include downloading in different formats, previews, file-level metadata preservation, file-level data citation; and exploration through data visualization and analysis. See the sections below for information about special functionality for specific file types. +File Previews +------------- + +Installations of Dataverse can install previewers for common file types uploaded by their research communities. The previews appear on the file page. If a preview tool for a specific file type is available, the preview will be created and will display automatically. File previews are not available for restricted files. Tabular Data Files ------------------ @@ -296,7 +300,7 @@ Here is an `example of a Data Usage Agreement configureTools; private List exploreTools; + private List toolsWithPreviews; @EJB DataFileServiceBean datafileService; @@ -208,7 +215,11 @@ public String init() { } configureTools = externalToolService.findFileToolsByTypeAndContentType(ExternalTool.Type.CONFIGURE, contentType); exploreTools = externalToolService.findFileToolsByTypeAndContentType(ExternalTool.Type.EXPLORE, contentType); - + Collections.sort(exploreTools, CompareExternalToolName); + toolsWithPreviews = addMapLayerAndSortExternalTools(); + if(!toolsWithPreviews.isEmpty()){ + setSelectedTool(toolsWithPreviews.get(0)); + } } else { return permissionsWrapper.notFound(); @@ -226,6 +237,30 @@ public FileMetadata getFileMetadata() { return fileMetadata; } + private List addMapLayerAndSortExternalTools(){ + List retList = externalToolService.findFileToolsByTypeContentTypeAndAvailablePreview(ExternalTool.Type.EXPLORE, file.getContentType()); + if(!retList.isEmpty()){ + retList.forEach((et) -> { + et.setWorldMapTool(false); + }); + } + if (file != null && worldMapPermissionHelper.getMapLayerMetadata(file) != null && worldMapPermissionHelper.getMapLayerMetadata(file).getEmbedMapLink() != null) { + ExternalTool wpTool = new ExternalTool(); + wpTool.setDisplayName("World Map"); + wpTool.setToolParameters("{}"); + wpTool.setToolUrl(worldMapPermissionHelper.getMapLayerMetadata(file).getEmbedMapLink()); + wpTool.setWorldMapTool(true); + retList.add(wpTool); + } + Collections.sort(retList, CompareExternalToolName); + + return retList; + } + + /* + worldMapPermissionHelper.getMapLayerMetadata(FilePage.fileMetadata.dataFile).getEmbedMapLink() + */ + public boolean isDownloadPopupRequired() { if(fileMetadata.getId() == null || fileMetadata.getDatasetVersion().getId() == null ){ @@ -888,10 +923,45 @@ public List getExploreTools() { return exploreTools; } + public List getToolsWithPreviews() { + return toolsWithPreviews; + } + + private ExternalTool selectedTool; + + public ExternalTool getSelectedTool() { + return selectedTool; + } + + public void setSelectedTool(ExternalTool selectedTool) { + this.selectedTool = selectedTool; + } + + public String preview(ExternalTool externalTool) { + ApiToken apiToken = null; + User user = session.getUser(); + if (user instanceof AuthenticatedUser) { + apiToken = authService.findApiTokenByUser((AuthenticatedUser) user); + } + if(externalTool == null){ + return ""; + } + ExternalToolHandler externalToolHandler = new ExternalToolHandler(externalTool, file, apiToken, file.getFileMetadata(), session.getLocaleCode()); + String toolUrl = externalToolHandler.getToolUrlForPreviewMode(); + return toolUrl; + } + //Provenance fragment bean calls this to show error dialogs after popup failure //This can probably be replaced by calling JsfHelper from the provpopup bean public void showProvError() { JH.addMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("file.metadataTab.provenance.error")); } + + private static final Comparator CompareExternalToolName = new Comparator() { + @Override + public int compare(ExternalTool o1, ExternalTool o2) { + return o1.getDisplayName().toUpperCase().compareTo(o2.getDisplayName().toUpperCase()); + } + }; } diff --git a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalTool.java b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalTool.java index 230b51e1e2c..7c7d17c19a1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalTool.java +++ b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalTool.java @@ -11,6 +11,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Transient; /** * A specification or definition for how an external tool is intended to @@ -27,6 +28,7 @@ public class ExternalTool implements Serializable { public static final String TOOL_URL = "toolUrl"; public static final String TOOL_PARAMETERS = "toolParameters"; public static final String CONTENT_TYPE = "contentType"; + public static final String HAS_PREVIEW_MODE = "hasPreviewMode"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -76,6 +78,22 @@ public class ExternalTool implements Serializable { */ @Column(nullable = true, columnDefinition = "TEXT") private String contentType; + + @Column(nullable = false) + private boolean hasPreviewMode; + + + + @Transient + private boolean worldMapTool; + + public boolean isWorldMapTool() { + return worldMapTool; + } + + public void setWorldMapTool(boolean worldMapTool) { + this.worldMapTool = worldMapTool; + } /** * This default constructor is only here to prevent this error at @@ -99,6 +117,18 @@ public ExternalTool(String displayName, String description, Type type, Scope sco this.toolUrl = toolUrl; this.toolParameters = toolParameters; this.contentType = contentType; + this.hasPreviewMode = false; + } + + public ExternalTool(String displayName, String description, Type type, Scope scope, String toolUrl, String toolParameters, String contentType, boolean hasPreviewMode) { + this.displayName = displayName; + this.description = description; + this.type = type; + this.scope = scope; + this.toolUrl = toolUrl; + this.toolParameters = toolParameters; + this.contentType = contentType; + this.hasPreviewMode = hasPreviewMode; } public enum Type { @@ -212,7 +242,15 @@ public String getContentType() { public void setContentType(String contentType) { this.contentType = contentType; } + + public boolean getHasPreviewMode() { + return hasPreviewMode; + } + public void setHasPreviewMode(boolean hasPreviewMode) { + this.hasPreviewMode = hasPreviewMode; + } + public JsonObjectBuilder toJson() { JsonObjectBuilder jab = Json.createObjectBuilder(); jab.add("id", getId()); @@ -224,6 +262,11 @@ public JsonObjectBuilder toJson() { jab.add(TOOL_PARAMETERS, getToolParameters()); if (getContentType() != null) { jab.add(CONTENT_TYPE, getContentType()); + } + if (getHasPreviewMode()) { + jab.add(HAS_PREVIEW_MODE, getHasPreviewMode()); + } else { + } return jab; } diff --git a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandler.java b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandler.java index 3f4781c0d27..a4a51666cc5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandler.java +++ b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolHandler.java @@ -101,6 +101,11 @@ public String getLocaleCode() { // TODO: rename to handleRequest() to someday handle sending headers as well as query parameters. public String getQueryParametersForUrl() { + return getQueryParametersForUrl(false); + } + + // TODO: rename to handleRequest() to someday handle sending headers as well as query parameters. + public String getQueryParametersForUrl(boolean preview) { String toolParameters = externalTool.getToolParameters(); JsonReader jsonReader = Json.createReader(new StringReader(toolParameters)); JsonObject obj = jsonReader.readObject(); @@ -118,7 +123,11 @@ public String getQueryParametersForUrl() { } }); }); - return "?" + String.join("&", params); + if (!preview) { + return "?" + String.join("&", params); + } else { + return "?" + String.join("&", params) + "&preview=true"; + } } private String getQueryParam(String key, String value) { @@ -178,6 +187,10 @@ private String getQueryParam(String key, String value) { public String getToolUrlWithQueryParams() { return externalTool.getToolUrl() + getQueryParametersForUrl(); } + + public String getToolUrlForPreviewMode() { + return externalTool.getToolUrl() + getQueryParametersForUrl(true); + } public ExternalTool getExternalTool() { return externalTool; diff --git a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBean.java index 6d3490750a3..8c49dd85fe0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBean.java @@ -14,6 +14,7 @@ import static edu.harvard.iq.dataverse.externaltools.ExternalTool.TYPE; import static edu.harvard.iq.dataverse.externaltools.ExternalTool.SCOPE; import static edu.harvard.iq.dataverse.externaltools.ExternalTool.CONTENT_TYPE; +import static edu.harvard.iq.dataverse.externaltools.ExternalTool.HAS_PREVIEW_MODE; import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -52,7 +53,8 @@ public List findAll() { */ public List findDatasetToolsByType(Type type) { String nullContentType = null; - return findByScopeTypeAndContentType(ExternalTool.Scope.DATASET, type, nullContentType); + String nullPreviewAvailable = null; + return findByScopeTypeAndContentType(ExternalTool.Scope.DATASET, type, nullContentType, nullPreviewAvailable); } /** @@ -61,7 +63,8 @@ public List findDatasetToolsByType(Type type) { */ public List findFileToolsByType(Type type) { String nullContentType = null; - return findByScopeTypeAndContentType(ExternalTool.Scope.FILE, type, nullContentType); + String nullPreviewAvailable = null; + return findByScopeTypeAndContentType(ExternalTool.Scope.FILE, type, nullContentType, nullPreviewAvailable); } /** @@ -70,7 +73,18 @@ public List findFileToolsByType(Type type) { * @return A list of tools or an empty list. */ public List findFileToolsByTypeAndContentType(Type type, String contentType) { - return findByScopeTypeAndContentType(ExternalTool.Scope.FILE, type, contentType); + String nullPreviewAvailable = null; + return findByScopeTypeAndContentType(ExternalTool.Scope.FILE, type, contentType, nullPreviewAvailable); + } + + /** + * @param type explore or configure + * @param contentType file content type (MIME type) + * @return A list of tools or an empty list. + */ + public List findFileToolsByTypeContentTypeAndAvailablePreview(Type type, String contentType) { + String previewAvailable = "true"; + return findByScopeTypeAndContentType(ExternalTool.Scope.FILE, type, contentType, previewAvailable); } /** @@ -79,13 +93,17 @@ public List findFileToolsByTypeAndContentType(Type type, String co * @param contentType file content type (MIME type) * @return A list of tools or an empty list. */ - private List findByScopeTypeAndContentType(Scope scope, Type type, String contentType) { + private List findByScopeTypeAndContentType(Scope scope, Type type, String contentType, String previewAvailable) { List externalTools = new ArrayList<>(); String contentTypeClause = ""; if (contentType != null) { contentTypeClause = "AND o.contentType = :contentType"; } - TypedQuery typedQuery = em.createQuery("SELECT OBJECT(o) FROM ExternalTool AS o WHERE o.scope = :scope AND o.type = :type " + contentTypeClause, ExternalTool.class); + String previewAvailableClause = ""; + if (previewAvailable != null) { + previewAvailableClause = " AND o.hasPreviewMode = 'true'"; + } + TypedQuery typedQuery = em.createQuery("SELECT OBJECT(o) FROM ExternalTool AS o WHERE o.scope = :scope AND o.type = :type " + contentTypeClause + previewAvailableClause, ExternalTool.class); typedQuery.setParameter("scope", scope); typedQuery.setParameter("type", type); if (contentType != null) { @@ -145,6 +163,7 @@ public static List findExternalToolsByFile(List allE } public static ExternalTool parseAddExternalToolManifest(String manifest) { + if (manifest == null || manifest.isEmpty()) { throw new IllegalArgumentException("External tool manifest was null or empty!"); } @@ -156,6 +175,7 @@ public static ExternalTool parseAddExternalToolManifest(String manifest) { String typeUserInput = getRequiredTopLevelField(jsonObject, TYPE); String scopeUserInput = getRequiredTopLevelField(jsonObject, SCOPE); String contentType = getOptionalTopLevelField(jsonObject, CONTENT_TYPE); + // Allow IllegalArgumentException to bubble up from ExternalTool.Type.fromString ExternalTool.Type type = ExternalTool.Type.fromString(typeUserInput); @@ -218,7 +238,15 @@ public static ExternalTool parseAddExternalToolManifest(String manifest) { } String toolParameters = toolParametersObj.toString(); - return new ExternalTool(displayName, description, type, scope, toolUrl, toolParameters, contentType); + + String hasPreviewMode = getOptionalTopLevelField(jsonObject, HAS_PREVIEW_MODE); + + boolean hasPreviewModeBoolean = false; + if(hasPreviewMode != null && hasPreviewMode.equals("true")){ + hasPreviewModeBoolean = true; + } + + return new ExternalTool(displayName, description, type, scope, toolUrl, toolParameters, contentType, hasPreviewModeBoolean); } private static String getRequiredTopLevelField(JsonObject jsonObject, String key) { diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index ddbea69e1d2..636a90287a0 100755 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -1458,7 +1458,6 @@ file.restricted.success=Files "{0}" will be restricted once you click on the Sav file.download.header=Download file.download.subset.header=Download Data Subset file.preview=Preview: -file.previewMap=Preview Map:o file.fileName=File Name file.type.tabularData=Tabular Data file.originalChecksumType=Original File {0} @@ -1641,6 +1640,9 @@ file.dataFilesTab.versions.description.beAccessedAt=The dataset can now be acces file.dataFilesTab.versions.viewDetails.btn=View Details file.dataFilesTab.versions.widget.viewMoreInfo=To view more information about the versions of this dataset, and to edit it if this is your dataset, please visit the full version of this dataset at the {2}. file.dataFilesTab.versions.preloadmessage=(Loading versions...) +file.previewTab.externalTools.header=Available Previews +file.previewTab.button.label=Previews +file.previewTab.previews.not.available=Public previews are not available for this file. file.deleteDialog.tip=Are you sure you want to delete this dataset and all of its files? You cannot undelete this dataset. file.deleteDialog.header=Delete Dataset file.deleteDraftDialog.tip=Are you sure you want to delete this draft version? Files will be reverted to the most recently published version. You cannot undelete this draft. @@ -1778,6 +1780,8 @@ file.tags.label=Tags file.lastupdated.label=Last Updated file.DatasetVersion=Version +file.previewTab.tool.open=Open +file.previewTab.header=Preview file.metadataTab.fileMetadata.header=File Metadata file.metadataTab.fileMetadata.persistentid.label=Data File Persistent ID file.metadataTab.fileMetadata.downloadUrl.label=Download URL diff --git a/src/main/resources/db/migration/V4.17.0.2__3578-file-page-preview.sql b/src/main/resources/db/migration/V4.17.0.2__3578-file-page-preview.sql new file mode 100644 index 00000000000..152700ed96c --- /dev/null +++ b/src/main/resources/db/migration/V4.17.0.2__3578-file-page-preview.sql @@ -0,0 +1,5 @@ +ALTER TABLE externalTool +ADD COLUMN IF NOT EXISTS hasPreviewMode BOOLEAN; +UPDATE externaltool SET hasPreviewMode = false; +ALTER TABLE externaltool ALTER COLUMN hasPreviewMode SET NOT NULL; + diff --git a/src/main/webapp/file-download-button-fragment.xhtml b/src/main/webapp/file-download-button-fragment.xhtml index 70759561aa3..36a38dac0e8 100644 --- a/src/main/webapp/file-download-button-fragment.xhtml +++ b/src/main/webapp/file-download-button-fragment.xhtml @@ -17,35 +17,6 @@ - - - - - diff --git a/src/main/webapp/file.xhtml b/src/main/webapp/file.xhtml index 219c4e8f5ac..4672a2b2e79 100644 --- a/src/main/webapp/file.xhtml +++ b/src/main/webapp/file.xhtml @@ -353,12 +353,12 @@
- + @@ -366,12 +366,84 @@ + + + + + +
+
+ + +
+ +
+
+ + + + + + + + + + + + + #{bundle['file.previewTab.tool.open']} #{bundle['file.mapData.worldMap']} + + + #{bundle['file.previewTab.tool.open']} #{bundle['file.mapData.worldMap']} + + + + + +
+
+ + - +
+
@@ -545,14 +616,8 @@
- - - - Coming soon... - - +
diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 553be5373e0..cdd50127957 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -278,7 +278,8 @@ static String getDatasetPersistentIdFromSwordResponse(Response createDatasetResp /** * @todo stop assuming the last 22 characters are the doi/globalId */ - return datasetSwordIdUrl.substring(datasetSwordIdUrl.length() - 22); + int doiPos = datasetSwordIdUrl.indexOf("doi"); + return datasetSwordIdUrl.substring(doiPos, datasetSwordIdUrl.length()); } public static Response getServiceDocument(String apiToken) { diff --git a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java index 34ba97584da..ea4f7676603 100644 --- a/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/externaltools/ExternalToolServiceBeanTest.java @@ -58,6 +58,7 @@ public void testParseAddExternalToolInput() { job.add("type", "explore"); job.add("scope", "file"); job.add("toolUrl", "http://awesometool.com"); + job.add("hasPreviewMode", "false"); job.add("toolParameters", Json.createObjectBuilder() .add("queryParameters", Json.createArrayBuilder() .add(Json.createObjectBuilder() @@ -105,6 +106,7 @@ public void testParseAddFileToolFilePid() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder() .add("queryParameters", Json.createArrayBuilder() @@ -154,6 +156,7 @@ public void testParseAddExternalToolInputNoFileId() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder() .add("queryParameters", Json.createArrayBuilder() @@ -206,6 +209,7 @@ public void testParseAddExternalToolInputUnknownReservedWord() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder() .add("queryParameters", Json.createArrayBuilder() @@ -238,6 +242,7 @@ public void testParseAddExternalToolInputNoDisplayName() { JsonObjectBuilder job = Json.createObjectBuilder(); job.add("description", "This tool is awesome."); job.add("toolUrl", "http://awesometool.com"); + job.add("hasPreviewMode", "false"); job.add("toolParameters", Json.createObjectBuilder().build()); job.add(ExternalTool.CONTENT_TYPE, DataFileServiceBean.MIME_TYPE_TSV_ALT); String tool = job.build().toString(); @@ -256,6 +261,7 @@ public void testParseAddExternalToolInputNoDisplayName() { public void testParseAddExternalToolInputNoDescription() { JsonObjectBuilder job = Json.createObjectBuilder(); job.add("displayName", "AwesomeTool"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder().build()); job.add(ExternalTool.CONTENT_TYPE, DataFileServiceBean.MIME_TYPE_TSV_ALT); @@ -278,6 +284,7 @@ public void testParseAddExternalToolInputNoToolUrl() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolParameters", Json.createObjectBuilder().build()); job.add(ExternalTool.CONTENT_TYPE, DataFileServiceBean.MIME_TYPE_TSV_ALT); String tool = job.build().toString(); @@ -299,6 +306,7 @@ public void testParseAddExternalToolInputWrongType() { job.add("description", "This tool is awesome."); job.add("type", "noSuchType"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder().build()); job.add(ExternalTool.CONTENT_TYPE, DataFileServiceBean.MIME_TYPE_TSV_ALT); @@ -322,6 +330,7 @@ public void testParseAddExternalToolInputNoContentType() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "file"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder().add("queryParameters", Json.createArrayBuilder() @@ -352,6 +361,7 @@ public void testParseAddDatasetToolNoRequiredFields() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "dataset"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder().add("queryParameters", Json.createArrayBuilder() @@ -380,6 +390,7 @@ public void testParseAddDatasetToolDatasetId() { job.add("type", "explore"); job.add("scope", "dataset"); job.add("toolUrl", "http://awesometool.com"); + job.add("hasPreviewMode", "true"); job.add("toolParameters", Json.createObjectBuilder().add("queryParameters", Json.createArrayBuilder() .add(Json.createObjectBuilder() @@ -410,6 +421,7 @@ public void testParseAddDatasetToolDatasetPid() { job.add("description", "This tool is awesome."); job.add("type", "explore"); job.add("scope", "dataset"); + job.add("hasPreviewMode", "false"); job.add("toolUrl", "http://awesometool.com"); job.add("toolParameters", Json.createObjectBuilder().add("queryParameters", Json.createArrayBuilder()