diff --git a/client/src/components/History/CurrentHistory/HistoryPanel.vue b/client/src/components/History/CurrentHistory/HistoryPanel.vue index 4352b5ec98a..3f48e13fbaf 100644 --- a/client/src/components/History/CurrentHistory/HistoryPanel.vue +++ b/client/src/components/History/CurrentHistory/HistoryPanel.vue @@ -14,7 +14,7 @@ import { useHistoryStore } from "@/stores/historyStore"; import { useUserStore } from "@/stores/userStore"; import { type Alias, getOperatorForAlias } from "@/utils/filtering"; import { setItemDragstart } from "@/utils/setDrag"; -import { startWatchingHistory } from "@/watch/watchHistory"; +import { startWatchingHistory } from "@/watch/watchHistoryProvided"; import { useHistoryDragDrop } from "../../../composables/historyDragDrop"; diff --git a/client/src/components/History/adapters/HistoryPanelProxy.js b/client/src/components/History/adapters/HistoryPanelProxy.js index e4336306bd2..83ba77ddf8b 100644 --- a/client/src/components/History/adapters/HistoryPanelProxy.js +++ b/client/src/components/History/adapters/HistoryPanelProxy.js @@ -6,7 +6,7 @@ import Backbone from "backbone"; import { createDatasetCollection } from "components/History/model/queries"; import { useHistoryItemsStore } from "stores/historyItemsStore"; import { useHistoryStore } from "stores/historyStore"; -import { startWatchingHistory } from "watch/watchHistory"; +import { startWatchingHistory } from "watch/watchHistoryProvided"; import { buildRuleCollectionModal } from "./buildCollectionModal"; diff --git a/client/src/components/RuleCollectionBuilder.vue b/client/src/components/RuleCollectionBuilder.vue index 301741f764e..615878b6faf 100644 --- a/client/src/components/RuleCollectionBuilder.vue +++ b/client/src/components/RuleCollectionBuilder.vue @@ -593,7 +593,7 @@ import _l from "utils/localization"; import Vue from "vue"; import { errorMessageAsString } from "@/utils/simple-error"; -import { startWatchingHistory } from "@/watch/watchHistory"; +import { startWatchingHistory } from "@/watch/watchHistoryProvided"; import TooltipOnHover from "components/TooltipOnHover.vue"; diff --git a/client/src/components/Tool/ToolForm.vue b/client/src/components/Tool/ToolForm.vue index 0202b782300..2c9c70bde24 100644 --- a/client/src/components/Tool/ToolForm.vue +++ b/client/src/components/Tool/ToolForm.vue @@ -122,7 +122,7 @@ import { canMutateHistory } from "@/api"; import { useConfigStore } from "@/stores/configurationStore"; import { useHistoryStore } from "@/stores/historyStore"; import { useUserStore } from "@/stores/userStore"; -import { startWatchingHistory } from "@/watch/watchHistory"; +import { startWatchingHistory } from "@/watch/watchHistoryProvided"; import ToolRecommendation from "../ToolRecommendation"; import { getToolFormData, submitJob, updateToolFormData } from "./services"; diff --git a/client/src/components/Workflow/Run/WorkflowRunSuccess.vue b/client/src/components/Workflow/Run/WorkflowRunSuccess.vue index 3f429ee6aae..eff42661c25 100644 --- a/client/src/components/Workflow/Run/WorkflowRunSuccess.vue +++ b/client/src/components/Workflow/Run/WorkflowRunSuccess.vue @@ -4,7 +4,7 @@ import { onMounted } from "vue"; import type { WorkflowInvocation } from "@/api/invocations"; import { useHistoryStore } from "@/stores/historyStore"; import Webhooks from "@/utils/webhooks"; -import { startWatchingHistory } from "@/watch/watchHistory"; +import { startWatchingHistory } from "@/watch/watchHistoryProvided"; import GridInvocation from "@/components/Grid/GridInvocation.vue"; import WorkflowInvocationState from "@/components/WorkflowInvocationState/WorkflowInvocationState.vue"; diff --git a/client/src/composables/resourceWatcher.ts b/client/src/composables/resourceWatcher.ts index 62b2d2567ef..4e7830da03d 100644 --- a/client/src/composables/resourceWatcher.ts +++ b/client/src/composables/resourceWatcher.ts @@ -1,4 +1,4 @@ -export type WatchResourceHandler = () => Promise; +export type WatchResourceHandler = (app?: T) => Promise; export interface WatchOptions { /** @@ -29,7 +29,10 @@ const DEFAULT_WATCH_OPTIONS: WatchOptions = { * @param watchHandler The handler function that watches the resource by querying the server. * @param options Options to customize the polling interval. */ -export function useResourceWatcher(watchHandler: WatchResourceHandler, options: WatchOptions = DEFAULT_WATCH_OPTIONS) { +export function useResourceWatcher( + watchHandler: WatchResourceHandler, + options: WatchOptions = DEFAULT_WATCH_OPTIONS +) { const { shortPollingInterval, longPollingInterval, enableBackgroundPolling } = { ...DEFAULT_WATCH_OPTIONS, ...options, @@ -41,9 +44,9 @@ export function useResourceWatcher(watchHandler: WatchResourceHandler, options: /** * Starts watching the resource by polling the server continuously. */ - function startWatchingResource() { + function startWatchingResource(app?: T) { stopWatcher(); - tryWatchResource(); + tryWatchResource(app); } /** @@ -60,15 +63,15 @@ export function useResourceWatcher(watchHandler: WatchResourceHandler, options: } } - async function tryWatchResource() { + async function tryWatchResource(app?: T) { try { - await watchHandler(); + await watchHandler(app); } catch (error) { console.warn(error); } finally { if (currentPollingInterval) { watchTimeout = setTimeout(() => { - tryWatchResource(); + tryWatchResource(app); }, currentPollingInterval); } } diff --git a/client/src/composables/userLocalStorage.ts b/client/src/composables/userLocalStorage.ts index d837c5a42d2..f4fe6971ade 100644 --- a/client/src/composables/userLocalStorage.ts +++ b/client/src/composables/userLocalStorage.ts @@ -1,37 +1,22 @@ -import { watchImmediate } from "@vueuse/core"; -import { type Ref, ref } from "vue"; +import { type Ref, type UnwrapRef } from "vue"; import { type AnyUser } from "@/api"; import { useHashedUserId } from "./hashedUserId"; import { useHashedUserId as useHashedUserIdFromStore } from "./hashedUserIdFromUserStore"; -import { syncRefToLocalStorage } from "./persistentRef"; +import { useUserLocalStorageFromHashId } from "./userLocalStorageFromHashedId"; /** * Local storage composable specific to current user. * @param key * @param initialValue */ -export function useUserLocalStorage(key: string, initialValue: T, user?: Ref) { +export function useUserLocalStorage(key: string, initialValue: T, user?: Ref): Ref> { let hashedUserId; if (user) { hashedUserId = useHashedUserId(user).hashedUserId; } else { hashedUserId = useHashedUserIdFromStore().hashedUserId; } - - const refToSync = ref(initialValue); - let hasSynced = false; - - watchImmediate( - () => hashedUserId.value, - () => { - if (hashedUserId.value && !hasSynced) { - syncRefToLocalStorage(`${key}-${hashedUserId.value}`, refToSync); - hasSynced = true; - } - } - ); - - return refToSync; + return useUserLocalStorageFromHashId(key, initialValue, hashedUserId); } diff --git a/client/src/composables/userLocalStorageFromHashedId.ts b/client/src/composables/userLocalStorageFromHashedId.ts new file mode 100644 index 00000000000..d5dbe6deef9 --- /dev/null +++ b/client/src/composables/userLocalStorageFromHashedId.ts @@ -0,0 +1,30 @@ +import { watchImmediate } from "@vueuse/core"; +import { type Ref, ref, type UnwrapRef } from "vue"; + +import { syncRefToLocalStorage } from "./persistentRef"; + +/** + * Local storage composable specific to current user. + * @param key + * @param initialValue + */ +export function useUserLocalStorageFromHashId( + key: string, + initialValue: T, + hashedUserId: Ref +): Ref> { + const refToSync = ref(initialValue); + let hasSynced = false; + + watchImmediate( + () => hashedUserId.value, + () => { + if (hashedUserId.value && !hasSynced) { + syncRefToLocalStorage(`${key}-${hashedUserId.value}`, refToSync); + hasSynced = true; + } + } + ); + + return refToSync; +} diff --git a/client/src/stores/userStore.ts b/client/src/stores/userStore.ts index b80ca670d3b..82088396a1e 100644 --- a/client/src/stores/userStore.ts +++ b/client/src/stores/userStore.ts @@ -2,7 +2,8 @@ import { defineStore } from "pinia"; import { computed, ref } from "vue"; import { type AnyUser, isAdminUser, isAnonymousUser, isRegisteredUser, type RegisteredUser } from "@/api"; -import { useUserLocalStorage } from "@/composables/userLocalStorage"; +import { useHashedUserId } from "@/composables/hashedUserId"; +import { useUserLocalStorageFromHashId } from "@/composables/userLocalStorageFromHashedId"; import { useHistoryStore } from "@/stores/historyStore"; import { addFavoriteToolQuery, @@ -28,14 +29,15 @@ type UserListViewPreferences = Record; export const useUserStore = defineStore("userStore", () => { const currentUser = ref(null); const currentPreferences = ref(null); + const { hashedUserId } = useHashedUserId(currentUser); - const currentListViewPreferences = useUserLocalStorage( + const currentListViewPreferences = useUserLocalStorageFromHashId( "user-store-list-view-preferences", {}, - currentUser + hashedUserId ); - const hasSeenUploadHelp = useUserLocalStorage("user-store-seen-upload-help", false, currentUser); + const hasSeenUploadHelp = useUserLocalStorageFromHashId("user-store-seen-upload-help", false, hashedUserId); let loadPromise: Promise | null = null; diff --git a/client/src/utils/data.js b/client/src/utils/data.js index fc2e4be4dac..68ae2fe8a46 100644 --- a/client/src/utils/data.js +++ b/client/src/utils/data.js @@ -89,6 +89,8 @@ function _mountSelectionDialog(clazz, options) { * TODO: This should live somewhere else. */ export function create(options) { + const galaxy = getGalaxyInstance(); + async function getHistory() { if (!options.history_id) { return getCurrentGalaxyHistory(); @@ -98,7 +100,7 @@ export function create(options) { getHistory().then((history_id) => { uploadSubmit({ success: (response) => { - startWatchingHistory(); + startWatchingHistory(galaxy); if (options.success) { options.success(response); } diff --git a/client/src/watch/watchHistory.js b/client/src/watch/watchHistory.js index 74dfcce033c..0a88b3ce3ea 100644 --- a/client/src/watch/watchHistory.js +++ b/client/src/watch/watchHistory.js @@ -5,7 +5,6 @@ * submitted, delayed only by the throttle period and the request response time. */ -import { getGalaxyInstance } from "app"; import { storeToRefs } from "pinia"; import { useHistoryItemsStore } from "stores/historyItemsStore"; import { useHistoryStore } from "stores/historyStore"; @@ -18,8 +17,8 @@ import { useDatasetStore } from "@/stores/datasetStore"; const limit = 1000; -const ACTIVE_POLLING_INTERVAL = 3000; -const INACTIVE_POLLING_INTERVAL = 60000; +export const ACTIVE_POLLING_INTERVAL = 3000; +export const INACTIVE_POLLING_INTERVAL = 60000; // last time the history has changed let lastUpdateTime = null; @@ -34,11 +33,12 @@ const { startWatchingResource: startWatchingHistory } = useResourceWatcher(watch export { startWatchingHistory }; -async function watchHistory() { +export async function watchHistory(app) { + // GalaxyApp const { isWatching } = storeToRefs(useHistoryItemsStore()); try { isWatching.value = true; - await watchHistoryOnce(); + await watchHistoryOnce(app); } catch (error) { // error alerting the user that watch history failed console.warn(error); @@ -46,7 +46,7 @@ async function watchHistory() { } } -export async function watchHistoryOnce() { +export async function watchHistoryOnce(app) { const historyStore = useHistoryStore(); const historyItemsStore = useHistoryItemsStore(); const datasetStore = useDatasetStore(); @@ -91,10 +91,9 @@ export async function watchHistoryOnce() { historyItemsStore.saveHistoryItems(historyId, payload); collectionElementsStore.saveCollections(payload); // trigger changes in legacy handler - const Galaxy = getGalaxyInstance(); - if (Galaxy) { - Galaxy.user.fetch({ - url: `${Galaxy.user.urlRoot()}/${Galaxy.user.id || "current"}`, + if (app) { + app.user.fetch({ + url: `${app.user.urlRoot()}/${app.user.id || "current"}`, }); } } diff --git a/client/src/watch/watchHistoryProvided.js b/client/src/watch/watchHistoryProvided.js new file mode 100644 index 00000000000..862b6ba6cb2 --- /dev/null +++ b/client/src/watch/watchHistoryProvided.js @@ -0,0 +1,21 @@ +import { getGalaxyInstance } from "app"; + +import { useResourceWatcher } from "@/composables/resourceWatcher"; + +import { + ACTIVE_POLLING_INTERVAL, + INACTIVE_POLLING_INTERVAL, + watchHistory as watchHistorySuppliedApp, +} from "./watchHistory"; + +function watchHistory() { + const app = getGalaxyInstance(); + return watchHistorySuppliedApp(app); +} + +const { startWatchingResource: startWatchingHistory } = useResourceWatcher(watchHistory, { + shortPollingInterval: ACTIVE_POLLING_INTERVAL, + longPollingInterval: INACTIVE_POLLING_INTERVAL, +}); + +export { startWatchingHistory };