@@ -38,7 +47,7 @@ function tutorialsInCategory(category: string) {
Tutorials
- There are {{ tutorialDetails.length }} tutorials available which use this tool.
+ {{ tutorialText }}
These tutorials include training for the current version of the tool.
From 6854cd10917fc99b7009128b414988b937358051 Mon Sep 17 00:00:00 2001
From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com>
Date: Tue, 21 Feb 2023 16:47:31 +0100
Subject: [PATCH 5/9] fix user select for ui-link
---
client/src/style/scss/ui.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/client/src/style/scss/ui.scss b/client/src/style/scss/ui.scss
index 244c6cb99b9..422f9d70685 100644
--- a/client/src/style/scss/ui.scss
+++ b/client/src/style/scss/ui.scss
@@ -416,6 +416,7 @@ $ui-margin-horizontal-large: $margin-v * 2;
display: inline;
line-height: unset;
vertical-align: unset;
+ user-select: text;
&:hover {
text-decoration: underline;
From 568624ce7014bcfd657fdf069091e85b1ff08fda Mon Sep 17 00:00:00 2001
From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com>
Date: Wed, 22 Feb 2023 11:41:23 +0100
Subject: [PATCH 6/9] match using tool id rename repository to owner
---
client/src/components/Tool/ToolCard.vue | 2 +-
.../Tool/ToolTutorialRecommendations.vue | 4 +-
.../src/composables/toolTrainingMaterial.ts | 52 ++++++++++++++-----
client/src/utils/regExp.ts | 10 ++++
doc/source/admin/galaxy_options.rst | 4 +-
lib/galaxy/config/sample/galaxy.yml.sample | 2 +-
lib/galaxy/config/schemas/config_schema.yml | 2 +-
7 files changed, 55 insertions(+), 21 deletions(-)
create mode 100644 client/src/utils/regExp.ts
diff --git a/client/src/components/Tool/ToolCard.vue b/client/src/components/Tool/ToolCard.vue
index 692b39faa3a..6e89980695a 100644
--- a/client/src/components/Tool/ToolCard.vue
+++ b/client/src/components/Tool/ToolCard.vue
@@ -170,7 +170,7 @@ function onUpdatePreferredObjectStoreId(selectedToolPreferredObjectStoreId) {
:id="props.options.id"
:name="props.options.name"
:version="props.options.version"
- :repository="props.options.tool_shed_repository?.owner" />
+ :owner="props.options.tool_shed_repository?.owner" />
Help
diff --git a/client/src/components/Tool/ToolTutorialRecommendations.vue b/client/src/components/Tool/ToolTutorialRecommendations.vue
index fbaad52a9fd..1d8cc5a7979 100644
--- a/client/src/components/Tool/ToolTutorialRecommendations.vue
+++ b/client/src/components/Tool/ToolTutorialRecommendations.vue
@@ -14,14 +14,14 @@ const props = defineProps<{
name: string;
id: string;
version: string;
- repository?: string;
+ owner?: string;
}>();
//@ts-ignore: bad library types
library.add(faCaretDown);
const { trainingAvailable, trainingCategories, tutorialDetails, allTutorialsUrl, versionAvailable } =
- useToolTrainingMaterial(props.id, props.name, props.version, props.repository);
+ useToolTrainingMaterial(props.id, props.name, props.version, props.owner);
const collapseId = useUid("collapse-");
diff --git a/client/src/composables/toolTrainingMaterial.ts b/client/src/composables/toolTrainingMaterial.ts
index 5f797c72a6d..f437d96271e 100644
--- a/client/src/composables/toolTrainingMaterial.ts
+++ b/client/src/composables/toolTrainingMaterial.ts
@@ -1,16 +1,11 @@
import { useConfig } from "./config";
import { computed, ref, watch, type Ref } from "vue";
-
-type Name = string;
-type Repo = string;
-type ID = string;
-
-type TrainingId = `${Repo}/${Name}` | ID;
+import { escapeRegExp } from "@/utils/regExp";
type TrainingDetails = {
tool_id: Array<
[
- string, // ID (unused)
+ string, // toolshed tool ID
string // Version
]
>;
@@ -25,7 +20,7 @@ type TrainingDetails = {
};
type TrainingMaterialResponse = {
- [id: TrainingId]: TrainingDetails;
+ [id: string]: TrainingDetails;
};
type Config = {
@@ -40,9 +35,30 @@ export type TutorialDetails = {
url: URL;
};
+/** caches the response of the training material api */
const cachedResponse: Ref
= ref(null);
-export function useToolTrainingMaterial(id: ID, name: Name, version: string, repo?: Repo) {
+/** maps toolshed tool ids to training tool ids */
+const toolIdMap: Map = new Map();
+
+function mapToolIds() {
+ Object.entries(cachedResponse.value ?? {}).forEach(([trainingId, details]) => {
+ details.tool_id.forEach(([id, version]) => {
+ if (id === version) {
+ // built-in tool
+ toolIdMap.set(id, trainingId);
+ } else {
+ const regEx = new RegExp(`${escapeRegExp(version)}$`);
+ const trimmedId = id.replace(regEx, "");
+
+ toolIdMap.set(trimmedId, trainingId);
+ }
+ });
+ });
+}
+
+/** Training information about given tool */
+export function useToolTrainingMaterial(id: string, name: string, version: string, owner?: string) {
const { config, isLoaded }: { config: Ref; isLoaded: Ref } = useConfig();
const apiEnabled = computed(() => {
return Boolean(
@@ -52,6 +68,8 @@ export function useToolTrainingMaterial(id: ID, name: Name, version: string, rep
);
});
+ const cacheLoaded = ref(false);
+
watch(
() => isLoaded.value,
async () => {
@@ -64,17 +82,23 @@ export function useToolTrainingMaterial(id: ID, name: Name, version: string, rep
if (res.ok) {
cachedResponse.value = await res.json();
+ mapToolIds();
}
}
+
+ cacheLoaded.value = true;
},
{ immediate: true }
);
const identifier = computed(() => {
- if (repo) {
- return `${repo}/${name.toLowerCase()}`;
+ const regEx = new RegExp(`${escapeRegExp(version)}$`);
+ const trimmedId = id.replace(regEx, "");
+
+ if (!cacheLoaded.value) {
+ return trimmedId;
} else {
- return id;
+ return toolIdMap.get(trimmedId) ?? trimmedId;
}
});
@@ -127,7 +151,7 @@ export function useToolTrainingMaterial(id: ID, name: Name, version: string, rep
});
const allTutorialsUrl = computed(() => {
- if (!isLoaded.value || !config.value.tool_training_recommendations_link) {
+ if (!cacheLoaded.value || !config.value.tool_training_recommendations_link) {
return;
}
@@ -136,7 +160,7 @@ export function useToolTrainingMaterial(id: ID, name: Name, version: string, rep
url = url.replace("{training_tool_identifier}", identifier.value);
url = url.replace("{tool_id}", id);
url = url.replace("{name}", name);
- url = url.replace("{repository}", repo ?? "");
+ url = url.replace("{repository_owner}", owner ?? "");
url = url.replace("{version}", version);
return url;
diff --git a/client/src/utils/regExp.ts b/client/src/utils/regExp.ts
new file mode 100644
index 00000000000..a9f4d733295
--- /dev/null
+++ b/client/src/utils/regExp.ts
@@ -0,0 +1,10 @@
+/**
+ * Escapes all RegExp control characters from a string, so it can be matched literally
+ * @param string input string
+ * @returns string with all control characters escaped
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
+ */
+export function escapeRegExp(string: string) {
+ return string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
diff --git a/doc/source/admin/galaxy_options.rst b/doc/source/admin/galaxy_options.rst
index 30093f71de5..72ac0c27914 100644
--- a/doc/source/admin/galaxy_options.rst
+++ b/doc/source/admin/galaxy_options.rst
@@ -5099,8 +5099,8 @@
:Description:
Template URL to display all tutorials containing current tool.
- Valid template inputs are: {repository} {name} {tool_id}
- {training_tool_identifier} {version}
+ Valid template inputs are: {repository_owner} {name}
+ {tool_id} {training_tool_identifier} {version}
:Default: ``https://training.galaxyproject.org/training-material/by-tool/{training_tool_identifier}.html``
:Type: str
diff --git a/lib/galaxy/config/sample/galaxy.yml.sample b/lib/galaxy/config/sample/galaxy.yml.sample
index 02261b95e66..0eeee9fe671 100644
--- a/lib/galaxy/config/sample/galaxy.yml.sample
+++ b/lib/galaxy/config/sample/galaxy.yml.sample
@@ -2717,7 +2717,7 @@ galaxy:
#tool_training_recommendations: true
# Template URL to display all tutorials containing current tool. Valid
- # template inputs are: {repository} {name} {tool_id}
+ # template inputs are: {repository_owner} {name} {tool_id}
# {training_tool_identifier} {version}
#tool_training_recommendations_link: https://training.galaxyproject.org/training-material/by-tool/{training_tool_identifier}.html
diff --git a/lib/galaxy/config/schemas/config_schema.yml b/lib/galaxy/config/schemas/config_schema.yml
index 7035f1e0d7f..16238812eb9 100644
--- a/lib/galaxy/config/schemas/config_schema.yml
+++ b/lib/galaxy/config/schemas/config_schema.yml
@@ -3715,7 +3715,7 @@ mapping:
desc: |
Template URL to display all tutorials containing current tool.
Valid template inputs are:
- {repository}
+ {repository_owner}
{name}
{tool_id}
{training_tool_identifier}
From fd56a9f1e59ee0af30dd5d32886f396b06706c16 Mon Sep 17 00:00:00 2001
From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com>
Date: Wed, 22 Feb 2023 11:45:36 +0100
Subject: [PATCH 7/9] move tutorials to bottom show help section conditionally
---
client/src/components/Tool/ToolCard.vue | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/client/src/components/Tool/ToolCard.vue b/client/src/components/Tool/ToolCard.vue
index 6e89980695a..744453d8642 100644
--- a/client/src/components/Tool/ToolCard.vue
+++ b/client/src/components/Tool/ToolCard.vue
@@ -166,13 +166,7 @@ function onUpdatePreferredObjectStoreId(selectedToolPreferredObjectStoreId) {
-
-
-
+
Help
@@ -184,6 +178,12 @@ function onUpdatePreferredObjectStoreId(selectedToolPreferredObjectStoreId) {
:license="props.options.license"
:creators="props.options.creators"
:requirements="props.options.requirements" />
+
+
From a8aa365fc007203b5b34f1eb1e28b32b96657898 Mon Sep 17 00:00:00 2001
From: Laila Los <44241786+ElectronicBlueberry@users.noreply.github.com>
Date: Wed, 22 Feb 2023 11:46:54 +0100
Subject: [PATCH 8/9] move tutorials above footer
---
client/src/components/Tool/ToolCard.vue | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/client/src/components/Tool/ToolCard.vue b/client/src/components/Tool/ToolCard.vue
index 744453d8642..4de127fc9db 100644
--- a/client/src/components/Tool/ToolCard.vue
+++ b/client/src/components/Tool/ToolCard.vue
@@ -171,6 +171,12 @@ function onUpdatePreferredObjectStoreId(selectedToolPreferredObjectStoreId) {
+
+
-
-