From 6f1344e9fc97af573a325d88660cad6cb24569e0 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 22 Mar 2024 18:23:55 -0700 Subject: [PATCH 01/13] do not expand datasets that are known to be inaccessible --- client/src/components/History/Content/ContentItem.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index e0d6acdb8178..19c8040201ab 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -9,6 +9,7 @@ import { useRoute, useRouter } from "vue-router/composables"; import type { ItemUrls } from "@/components/History/Content/Dataset/index"; import { updateContentFields } from "@/components/History/model/queries"; +import { Toast } from "@/composables/toast"; import { useEntryPointStore } from "@/stores/entryPointStore"; import { useEventStore } from "@/stores/eventStore"; import { clearDrag } from "@/utils/setDrag"; @@ -238,7 +239,11 @@ function onClick(e?: Event) { return; } if (props.isDataset) { - emit("update:expand-dataset", !props.expandDataset); + if (props.item.accessible === false) { + Toast.error(`You are not allowed to access this dataset`); + } else { + emit("update:expand-dataset", !props.expandDataset); + } } else { emit("view-collection", props.item, props.name); } From fb77ea2db4100ea2774589fe828e6c45a0385c5c Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Mon, 25 Mar 2024 15:52:59 -0700 Subject: [PATCH 02/13] include HDAInaccessible in AnyHDA union I assume the union_mode does not trickle down... type accessible as literal False --- client/src/api/schema/schema.ts | 96 ++++++++++++++++++++++++++++++++- lib/galaxy/schema/schema.py | 4 +- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index cb7b0dc21217..13de4b70d8e5 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -5997,6 +5997,87 @@ export interface components { */ visible: boolean; }; + /** + * HDAInaccessible + * @description History Dataset Association information when the user can not access it. + */ + HDAInaccessible: { + /** + * Accessible + * @constant + */ + accessible: Record; + /** Copied From Ldda Id */ + copied_from_ldda_id?: string | null; + /** + * Create Time + * @description The time and date this item was created. + */ + create_time: string | null; + /** + * Deleted + * @description Whether this item is marked as deleted. + */ + deleted: boolean; + /** + * HID + * @description The index position of this item in the History. + */ + hid: number; + /** + * History Content Type + * @description This is always `dataset` for datasets. + * @constant + */ + history_content_type: "dataset"; + /** + * History ID + * @example 0123456789ABCDEF + */ + history_id: string; + /** + * Id + * @example 0123456789ABCDEF + */ + id: string; + /** + * Name + * @description The name of the item. + */ + name: string | null; + /** + * State + * @description The current state of this dataset. + */ + state: components["schemas"]["DatasetState"]; + tags: components["schemas"]["TagCollection"]; + /** + * Type + * @description The type of this item. + */ + type: string; + /** + * Type - ID + * @description The type and the encoded ID of this item. Used for caching. + */ + type_id?: string | null; + /** + * Update Time + * @description The last time and date this item was updated. + */ + update_time: string | null; + /** + * URL + * @deprecated + * @description The relative URL to access this item. + */ + url: string; + /** + * Visible + * @description Whether this item is visible or hidden to the user by default. + */ + visible: boolean; + }; /** * HDAObject * @description History Dataset Association Object @@ -6924,6 +7005,7 @@ export interface components { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; @@ -6940,6 +7022,7 @@ export interface components { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; @@ -13530,6 +13613,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; @@ -13710,7 +13794,8 @@ export interface operations { "application/json": | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] - | components["schemas"]["HDASummary"]; + | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"]; }; }; /** @description Validation Error */ @@ -16460,12 +16545,14 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] | ( | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; @@ -17049,6 +17136,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"]; }; @@ -17100,6 +17188,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"]; }; @@ -17332,12 +17421,14 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] | ( | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; @@ -17388,6 +17479,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"]; }; @@ -17438,6 +17530,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"]; }; @@ -17669,6 +17762,7 @@ export interface operations { | components["schemas"]["HDACustom"] | components["schemas"]["HDADetailed"] | components["schemas"]["HDASummary"] + | components["schemas"]["HDAInaccessible"] | components["schemas"]["HDCADetailed"] | components["schemas"]["HDCASummary"] )[]; diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 34fe24988095..9e9360d56764 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -688,7 +688,7 @@ class HDASummary(HDACommon): class HDAInaccessible(HDACommon): """History Dataset Association information when the user can not access it.""" - accessible: bool = AccessibleField + accessible: Literal[False] state: DatasetStateField @@ -3271,7 +3271,7 @@ class HDACustom(HDADetailed): model_config = ConfigDict(extra="allow") -AnyHDA = Union[HDACustom, HDADetailed, HDASummary] +AnyHDA = Union[HDACustom, HDADetailed, HDASummary, HDAInaccessible] AnyHDCA = Union[HDCADetailed, HDCASummary] AnyHistoryContentItem = Annotated[ Union[ From 422d7879d2a5f35d9775e776db626cc2b2cfa613 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Wed, 27 Mar 2024 17:21:57 -0700 Subject: [PATCH 03/13] reintroduce missing inaccessible state that does not fetch dataset details or allow other interactions minor adjustments --- .../History/Content/ContentItem.vue | 29 ++++++++++++------- .../History/Content/model/states.ts | 14 ++++++++- client/src/style/scss/base.scss | 2 ++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index 19c8040201ab..6cd89d478b24 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -9,7 +9,6 @@ import { useRoute, useRouter } from "vue-router/composables"; import type { ItemUrls } from "@/components/History/Content/Dataset/index"; import { updateContentFields } from "@/components/History/model/queries"; -import { Toast } from "@/composables/toast"; import { useEntryPointStore } from "@/stores/entryPointStore"; import { useEventStore } from "@/stores/eventStore"; import { clearDrag } from "@/utils/setDrag"; @@ -92,7 +91,9 @@ const contentId = computed(() => { const contentCls = computed(() => { const status = contentState.value && contentState.value.status; - if (props.selected) { + if (props.item.accessible === false) { + return "alert-inaccessible"; + } else if (props.selected) { return "alert-info"; } else if (!status) { return `alert-success`; @@ -100,7 +101,6 @@ const contentCls = computed(() => { return `alert-${status}`; } }); - const contentState = computed(() => { return STATES[state.value] && STATES[state.value]; }); @@ -117,6 +117,9 @@ const state = computed(() => { if (props.isPlaceholder) { return "placeholder"; } + if (props.item.accessible === false) { + return "inaccessible"; + } if (props.item.populated_state === "failed") { return "failed_populated_state"; } @@ -136,7 +139,13 @@ const state = computed(() => { }); const dataState = computed(() => { - return state.value === "new_populated_state" ? "new" : state.value; + if (props.item.accessible === false) { + return "inaccessible"; + } else if (state.value === "new_populated_state") { + return "new"; + } else { + return state.value; + } }); const tags = computed(() => { @@ -239,11 +248,7 @@ function onClick(e?: Event) { return; } if (props.isDataset) { - if (props.item.accessible === false) { - Toast.error(`You are not allowed to access this dataset`); - } else { - emit("update:expand-dataset", !props.expandDataset); - } + emit("update:expand-dataset", !props.expandDataset); } else { emit("view-collection", props.item, props.name); } @@ -433,8 +438,12 @@ function unexpandedClick(event: Event) { +
+ You are not allowed to access this dataset + {{ item.id }} +
Date: Wed, 27 Mar 2024 17:24:05 -0700 Subject: [PATCH 04/13] fix a bug with using a supposedly optional caching key for a required operation --- client/src/components/History/CurrentHistory/HistoryPanel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index 5e287c961ec2..074af66947c0 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -418,7 +418,7 @@ function updateFilterValue(filterKey: string, newValue: any) { } function getItemKey(item: HistoryItem) { - return item.type_id; + return itemUniqueKey(item); } function itemUniqueKey(item: HistoryItem) { From 743a5f3c32451076ce79efd891835f286cc25bae Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Wed, 27 Mar 2024 17:34:08 -0700 Subject: [PATCH 05/13] remove debug --- client/src/components/History/Content/ContentItem.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index 6cd89d478b24..c515a952c3f7 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -438,10 +438,7 @@ function unexpandedClick(event: Event) { -
- You are not allowed to access this dataset - {{ item.id }} -
+
You are not allowed to access this dataset
Date: Fri, 29 Mar 2024 09:29:20 -0700 Subject: [PATCH 06/13] prevent id conflict between hda and dataset --- .../components/History/CurrentCollection/CollectionPanel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/History/CurrentCollection/CollectionPanel.vue b/client/src/components/History/CurrentCollection/CollectionPanel.vue index 10c830ca4601..be760caaa42d 100644 --- a/client/src/components/History/CurrentCollection/CollectionPanel.vue +++ b/client/src/components/History/CurrentCollection/CollectionPanel.vue @@ -76,7 +76,7 @@ function updateDsc(collection: any, fields: Object | undefined) { } function getItemKey(item: DCESummary) { - return item.id; + return `${item.element_type}-${item.id}`; } function onScroll(newOffset: number) { From 3bfdd3e08f268379266b239f00dc973479388ddb Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 29 Mar 2024 11:28:30 -0700 Subject: [PATCH 07/13] do not show storage selection to anons --- .../components/History/CurrentHistory/HistoryCounter.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/History/CurrentHistory/HistoryCounter.vue b/client/src/components/History/CurrentHistory/HistoryCounter.vue index 98efa0bf11b8..272a93c3ce9c 100644 --- a/client/src/components/History/CurrentHistory/HistoryCounter.vue +++ b/client/src/components/History/CurrentHistory/HistoryCounter.vue @@ -46,7 +46,7 @@ const emit = defineEmits(["update:filter-text", "reloadContents"]); const router = useRouter(); const { config } = useConfig(); -const { currentUser } = storeToRefs(useUserStore()); +const { currentUser, isAnonymous } = storeToRefs(useUserStore()); const { historySize, numItemsActive, numItemsDeleted, numItemsHidden } = useDetailedHistory(toRef(props, "history")); const reloadButtonLoading = ref(false); @@ -145,7 +145,7 @@ onMounted(() => { { From a5b208bea461966ba6eb6bbb9390cfec2ddf94cb Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 29 Mar 2024 12:09:38 -0700 Subject: [PATCH 08/13] make inaccessible items non-draggable --- client/src/components/History/Content/ContentItem.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/History/Content/ContentItem.vue b/client/src/components/History/Content/ContentItem.vue index c515a952c3f7..cba8f0bdc4d3 100644 --- a/client/src/components/History/Content/ContentItem.vue +++ b/client/src/components/History/Content/ContentItem.vue @@ -344,7 +344,7 @@ function unexpandedClick(event: Event) { :data-state="dataState" tabindex="0" role="button" - draggable + :draggable="props.item.accessible === false ? false : true" @dragstart="onDragStart" @dragend="onDragEnd" @keydown="onKeyDown"> From 7961b475bbd80ceb8bdd615b1e6eb0c67a9ff2a1 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 24 May 2024 10:47:32 +0200 Subject: [PATCH 09/13] Fix bool const OpenAPI TS schema conversion --- client/openapi_to_schema.mjs | 14 +++++++++----- client/src/api/schema/schema.ts | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/client/openapi_to_schema.mjs b/client/openapi_to_schema.mjs index eb6e22a290cc..d85b349f096d 100644 --- a/client/openapi_to_schema.mjs +++ b/client/openapi_to_schema.mjs @@ -7,11 +7,15 @@ const inputFilePath = process.argv[2]; const localPath = new URL(inputFilePath, import.meta.url); openapiTS(localPath, { transform(schemaObject, metadata) { - if ( - "const" in schemaObject && - (typeof schemaObject.const === "string" || schemaObject.const instanceof String) - ) { - return `"${schemaObject.const}"`; + if ("const" in schemaObject) { + const constType = typeof schemaObject.const; + switch (constType) { + case "number": + case "boolean": + return `${schemaObject.const}`; + default: + return `"${schemaObject.const}"`; + } } }, }).then((output) => console.log(output)); diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 13de4b70d8e5..d48a58025dad 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -6006,7 +6006,7 @@ export interface components { * Accessible * @constant */ - accessible: Record; + accessible: false; /** Copied From Ldda Id */ copied_from_ldda_id?: string | null; /** From afac2afa24664e19a751e7c59ea697de1566d13b Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 24 May 2024 10:50:08 +0200 Subject: [PATCH 10/13] Serialize accessible field for collection elements --- client/src/api/schema/schema.ts | 2 ++ lib/galaxy/schema/schema.py | 1 + lib/galaxy/webapps/galaxy/services/dataset_collections.py | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index d48a58025dad..36a71aa1d4e1 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -6083,6 +6083,8 @@ export interface components { * @description History Dataset Association Object */ HDAObject: { + /** Accessible */ + accessible: boolean; /** Copied From Ldda Id */ copied_from_ldda_id?: string | null; /** diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 9e9360d56764..aeadf4d8874e 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -939,6 +939,7 @@ class HDAObject(Model, WithModelClass): history_id: HistoryID tags: List[str] copied_from_ldda_id: Optional[EncodedDatabaseIdField] = None + accessible: bool model_config = ConfigDict(extra="allow") diff --git a/lib/galaxy/webapps/galaxy/services/dataset_collections.py b/lib/galaxy/webapps/galaxy/services/dataset_collections.py index 25fcdb61f0aa..40d32be49e7e 100644 --- a/lib/galaxy/webapps/galaxy/services/dataset_collections.py +++ b/lib/galaxy/webapps/galaxy/services/dataset_collections.py @@ -24,6 +24,7 @@ dictify_element_reference, ) from galaxy.managers.context import ProvidesHistoryContext +from galaxy.managers.hdas import HDAManager from galaxy.managers.hdcas import HDCAManager from galaxy.managers.histories import HistoryManager from galaxy.model import DatasetCollectionElement @@ -94,12 +95,14 @@ def __init__( self, security: IdEncodingHelper, history_manager: HistoryManager, + hda_manager: HDAManager, hdca_manager: HDCAManager, collection_manager: DatasetCollectionManager, datatypes_registry: Registry, ): super().__init__(security) self.history_manager = history_manager + self.hda_manager = hda_manager self.hdca_manager = hdca_manager self.collection_manager = collection_manager self.datatypes_registry = datatypes_registry @@ -270,6 +273,8 @@ def serialize_element(dsc_element) -> DCESummary: hdca_id=self.encode_id(hdca.id), parent_id=self.encode_id(result["object"]["id"]), ) + else: + result["object"]["accessible"] = self.hda_manager.is_accessible(dsc_element.element_object, trans.user) return result rval = [serialize_element(el) for el in contents] From a0adf7e76bb17db36d1bb14cd64bc83e68bd4b8d Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 24 May 2024 10:53:00 +0200 Subject: [PATCH 11/13] Add missing event declaration Fixes typescript error: Argument of type '"edit"' is not assignable to parameter of type '"toggleHighlights"' --- client/src/components/History/Content/Dataset/DatasetDetails.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/History/Content/Dataset/DatasetDetails.vue b/client/src/components/History/Content/Dataset/DatasetDetails.vue index 5cf6b2880e1d..ad083eb75584 100644 --- a/client/src/components/History/Content/Dataset/DatasetDetails.vue +++ b/client/src/components/History/Content/Dataset/DatasetDetails.vue @@ -26,6 +26,7 @@ const props = withDefaults(defineProps(), { const emit = defineEmits<{ (e: "toggleHighlights"): void; + (e: "edit"): void; }>(); const result = computed(() => datasetStore.getDataset(props.id)); From 810b246fbf6872b268c2ab68043884c9aa0777e3 Mon Sep 17 00:00:00 2001 From: davelopez <46503462+davelopez@users.noreply.github.com> Date: Fri, 24 May 2024 10:53:51 +0200 Subject: [PATCH 12/13] Avoid requesting details for inaccessible datasets --- client/src/api/index.ts | 11 ++++++++++- .../History/Content/Dataset/DatasetDetails.vue | 3 ++- client/src/stores/collectionElementsStore.test.ts | 1 + client/src/stores/datasetStore.ts | 5 ++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/client/src/api/index.ts b/client/src/api/index.ts index a32e076b84ff..75574ac0834b 100644 --- a/client/src/api/index.ts +++ b/client/src/api/index.ts @@ -89,6 +89,11 @@ export type DatasetSummary = components["schemas"]["HDASummary"]; */ export type DatasetDetails = components["schemas"]["HDADetailed"]; +/** + * Represents a HistoryDatasetAssociation that is inaccessible to the user. + */ +export type HDAInaccessible = components["schemas"]["HDAInaccessible"]; + /** * Contains storage (object store, quota, etc..) details for a dataset. */ @@ -97,7 +102,7 @@ export type DatasetStorageDetails = components["schemas"]["DatasetStorageDetails /** * Represents a HistoryDatasetAssociation with either summary or detailed information. */ -export type DatasetEntry = DatasetSummary | DatasetDetails; +export type DatasetEntry = DatasetSummary | DatasetDetails | HDAInaccessible; /** * Contains summary information about a DCE (DatasetCollectionElement). @@ -183,6 +188,10 @@ export function hasDetails(entry: DatasetEntry): entry is DatasetDetails { return "peek" in entry; } +export function isInaccessible(entry: DatasetEntry): entry is HDAInaccessible { + return "accessible" in entry && !entry.accessible; +} + /** * Contains dataset metadata information. */ diff --git a/client/src/components/History/Content/Dataset/DatasetDetails.vue b/client/src/components/History/Content/Dataset/DatasetDetails.vue index ad083eb75584..2dcae1313163 100644 --- a/client/src/components/History/Content/Dataset/DatasetDetails.vue +++ b/client/src/components/History/Content/Dataset/DatasetDetails.vue @@ -2,6 +2,7 @@ import { BLink } from "bootstrap-vue"; import { computed } from "vue"; +import { hasDetails } from "@/api"; import { STATES } from "@/components/History/Content/model/states"; import { useDatasetStore } from "@/stores/datasetStore"; @@ -41,7 +42,7 @@ function toggleHighlights() {