Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 0 additions & 103 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3783,26 +3783,6 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/metrics": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Records a collection of metrics.
* @description Record any metrics sent and return some status object.
*/
post: operations["create_api_metrics_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/notifications": {
parameters: {
query?: never;
Expand Down Expand Up @@ -9431,20 +9411,6 @@ export interface components {
/** State */
state?: string | null;
};
/** CreateMetricsPayload */
CreateMetricsPayload: {
/**
* List of metrics to be recorded.
* @default []
* @example {
* "args": "{\"test\":\"value\"}",
* "level": 0,
* "namespace": "test-source",
* "time": "2021-01-23T18:25:43.511Z"
* }
*/
metrics: components["schemas"]["Metric"][];
};
/** CreateNewCollectionPayload */
CreateNewCollectionPayload: {
/**
Expand Down Expand Up @@ -18969,30 +18935,6 @@ export interface components {
*/
file_type: string;
};
/** Metric */
Metric: {
/**
* Arguments
* @description A JSON string containing an array of extra data.
*/
args: string;
/**
* Level
* @description An integer representing the metric's log level.
*/
level: number;
/**
* Namespace
* @description Label indicating the source of the metric.
*/
namespace: string;
/**
* Timestamp
* @description The timestamp in ISO format.
* @example 2021-01-23T18:25:43.511Z
*/
time: string;
};
/**
* ModelStoreFormat
* @description Available types of model stores for export.
Expand Down Expand Up @@ -38008,51 +37950,6 @@ export interface operations {
};
};
};
create_api_metrics_post: {
parameters: {
query?: never;
header?: {
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
"run-as"?: string | null;
};
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["CreateMetricsPayload"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": unknown;
};
};
/** @description Request Error */
"4XX": {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MessageExceptionModel"];
};
};
/** @description Server Error */
"5XX": {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["MessageExceptionModel"];
};
};
};
};
get_user_notifications_api_notifications_get: {
parameters: {
query?: {
Expand Down
13 changes: 5 additions & 8 deletions client/src/components/ToolsList/ToolsListTable.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { BAlert } from "bootstrap-vue";
import { storeToRefs } from "pinia";
import { watchEffect } from "vue";
import { computed } from "vue";

import { type Tool, useToolStore } from "@/stores/toolStore";

Expand Down Expand Up @@ -42,18 +42,15 @@ async function loadTools(offset: number, limit: number): Promise<{ items: Tool[]
return { items, total: props.tools.length };
}

// Watch for changes in tools array to preload initial help data
watchEffect(() => {
if (props.tools.length > 0) {
const initialItems = props.tools.slice(0, FETCH_LIMIT + PREFETCH_AHEAD);
Promise.all(initialItems.map((tool) => toolStore.fetchHelpForId(tool.id)));
}
});
// Force ScrollList remount when tools change (e.g. after search),
// ensuring loadTools is called again to await help data for new results.
const toolsKey = computed(() => `${props.tools.length}-${props.tools[0]?.id}`);
</script>

<template>
<ScrollList
ref="root"
:key="toolsKey"
:loader="loadTools"
:limit="FETCH_LIMIT"
:item-key="(tool) => tool.id"
Expand Down
25 changes: 16 additions & 9 deletions client/src/stores/toolStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const useToolStore = defineStore("toolStore", () => {
const toolsById = shallowRef<Record<string, Tool>>({});
const toolResults = ref<Record<string, string[]>>({});
const toolSections = ref<Record<string, Record<string, Tool | ToolSection>>>({});
const fetchedHelpIds = ref<Set<string>>(new Set());
const fetchedHelpIds = ref<Map<string, Promise<void>>>(new Map());
const helpDataCached = ref<Record<string, ToolHelpData>>({});

const currentToolSections = computed(() => {
Expand Down Expand Up @@ -245,10 +245,15 @@ export const useToolStore = defineStore("toolStore", () => {
}

async function fetchHelpForId(toolId: string) {
try {
if (!helpDataCached.value[toolId] && !fetchedHelpIds.value.has(toolId)) {
fetchedHelpIds.value.add(toolId);

if (helpDataCached.value[toolId]) {
return;
}
const existing = fetchedHelpIds.value.get(toolId);
if (existing) {
return existing;
}
const promise = (async () => {
try {
const toolHelpData: ToolHelpData = {};

const { data } = (await axios.get(
Expand All @@ -264,11 +269,13 @@ export const useToolStore = defineStore("toolStore", () => {
}

Vue.set(helpDataCached.value, toolId, toolHelpData);
} catch (error) {
console.error("Error fetching help:", error);
fetchedHelpIds.value.delete(toolId); // Allow retrying on next request
}
} catch (error) {
console.error("Error fetching help:", error);
fetchedHelpIds.value.delete(toolId); // Allow retrying on next request
}
})();
fetchedHelpIds.value.set(toolId, promise);
return promise;
}

async function initializePanel() {
Expand Down
9 changes: 8 additions & 1 deletion lib/galaxy/files/sources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,14 @@ def to_relative_path(self, url: str) -> str:

def score_url_match(self, url: str) -> int:
root = self.get_uri_root()
return len(root) if root in url else 0
if url.startswith(root):
rest = url[len(root) :]
# For roots with a prefix (e.g. gxfiles://test1), ensure match is
# at a boundary so gxfiles://test1http://evil doesn't match test1.
# Roots ending with :// (e.g. gxftp://) don't need this check.
if root.endswith("://") or not rest or rest.startswith("/"):
return len(root)
return 0

def uri_from_path(self, path: str) -> str:
uri_root = self.get_uri_root()
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/managers/genomes.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def _get_index_filename(self, id, tbl_entries, ext, index_type):
except TypeError:
raise ReferenceDataError(f"Data tables not found for {index_type}")
except IndexError:
raise ReferenceDataError(f"Data tables not found for {index_type} for {id}")
raise RequestParameterInvalidException(f"Data tables not found for {index_type} for {id}")
else:
return f"{file_name}{ext}"

Expand Down
139 changes: 0 additions & 139 deletions lib/galaxy/managers/metrics.py

This file was deleted.

4 changes: 4 additions & 0 deletions lib/galaxy/managers/remote_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def index(

if "://" in target:
uri = target
# Reject URIs with embedded schemes (e.g. gxfiles://foo_http://evil.com)
scheme_end = uri.index("://") + 3
if "://" in uri[scheme_end:]:
raise exceptions.RequestParameterInvalidException(f"Malformed URI: {uri}")
elif target == RemoteFilesTarget.userdir:
uri = "gxuserimport://"
default_format = RemoteFilesFormat.flat
Expand Down
Loading
Loading