Created
March 3, 2025 20:30
-
-
Save dannon/805146a51511dbf90281979eeae2fe82 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/client/src/api/index.ts b/client/src/api/index.ts | |
index 6f9ce9d021..361c02a8e0 100644 | |
--- a/client/src/api/index.ts | |
+++ b/client/src/api/index.ts | |
@@ -266,6 +266,7 @@ export function isRegisteredUser(user: AnyUser | UserModel): user is RegisteredU | |
} | |
export function isAnonymousUser(user: AnyUser | UserModel): user is AnonymousUser { | |
+ console.debug("CHECKING IS ANONYMOUS USER ", user); | |
return user !== null && !isRegisteredUser(user); | |
} | |
diff --git a/client/src/components/Landing/WorkflowLanding.vue b/client/src/components/Landing/WorkflowLanding.vue | |
index 2677d0a09b..503b9620b2 100644 | |
--- a/client/src/components/Landing/WorkflowLanding.vue | |
+++ b/client/src/components/Landing/WorkflowLanding.vue | |
@@ -1,12 +1,8 @@ | |
<script setup lang="ts"> | |
import { BAlert } from "bootstrap-vue"; | |
-import { storeToRefs } from "pinia"; | |
-import { ref, watch } from "vue"; | |
-import { useRouter } from "vue-router/composables"; | |
+import { onMounted, ref } from "vue"; | |
import { GalaxyApi } from "@/api"; | |
-import { useActivityStore } from "@/stores/activityStore"; | |
-import { useUserStore } from "@/stores/userStore"; | |
import { errorMessageAsString } from "@/utils/simple-error"; | |
import LoadingSpan from "@/components/LoadingSpan.vue"; | |
@@ -27,56 +23,42 @@ const workflowId = ref<string | null>(null); | |
const errorMessage = ref<string | null>(null); | |
const requestState = ref<Record<string, never> | null>(null); | |
const instance = ref<boolean>(false); | |
-const userStore = useUserStore(); | |
-const router = useRouter(); | |
-userStore.loadUser(false); | |
-const { isAnonymous, currentUser } = storeToRefs(userStore); | |
+onMounted(async () => { | |
+ let claim; | |
+ let claimError; | |
-const activityStore = useActivityStore("default"); | |
+ if (props.public) { | |
+ const { data, error } = await GalaxyApi().GET("/api/workflow_landings/{uuid}", { | |
+ params: { | |
+ path: { uuid: props.uuid }, | |
+ }, | |
+ }); | |
+ claim = data; | |
+ claimError = error; | |
+ } else { | |
+ const { data, error } = await GalaxyApi().POST("/api/workflow_landings/{uuid}/claim", { | |
+ params: { | |
+ path: { uuid: props.uuid }, | |
+ }, | |
+ body: { | |
+ client_secret: props.secret, | |
+ }, | |
+ }); | |
+ claim = data; | |
+ claimError = error; | |
+ } | |
-watch( | |
- currentUser, | |
- async () => { | |
- if (isAnonymous.value) { | |
- router.push( | |
- `/login/start?redirect=/workflow_landings/${props.uuid}?public=${props.public}&client_secret=${props.secret}` | |
- ); | |
- } else if (currentUser.value) { | |
- let claim; | |
- let claimError; | |
- activityStore.closeSideBar(); | |
- if (props.public) { | |
- const { data, error } = await GalaxyApi().GET("/api/workflow_landings/{uuid}", { | |
- params: { | |
- path: { uuid: props.uuid }, | |
- }, | |
- }); | |
- claim = data; | |
- claimError = error; | |
- } else { | |
- const { data, error } = await GalaxyApi().POST("/api/workflow_landings/{uuid}/claim", { | |
- params: { | |
- path: { uuid: props.uuid }, | |
- }, | |
- body: { | |
- client_secret: props.secret, | |
- }, | |
- }); | |
- claim = data; | |
- claimError = error; | |
- } | |
- if (claim) { | |
- workflowId.value = claim.workflow_id; | |
- instance.value = claim.workflow_target_type === "workflow"; | |
- requestState.value = claim.request_state; | |
- } else { | |
- errorMessage.value = errorMessageAsString(claimError); | |
- } | |
- } | |
- }, | |
- { immediate: true } | |
-); | |
+ if (claim) { | |
+ workflowId.value = claim.workflow_id; | |
+ instance.value = claim.workflow_target_type === "workflow"; | |
+ requestState.value = claim.request_state; | |
+ } else { | |
+ errorMessage.value = errorMessageAsString(claimError); | |
+ } | |
+ const activityStore = useActivityStore("default"); | |
+ activityStore.closeSideBar(); | |
+}); | |
</script> | |
<template> | |
diff --git a/client/src/composables/hashedUserId.ts b/client/src/composables/hashedUserId.ts | |
index a7f651a3c6..a40529ee86 100644 | |
--- a/client/src/composables/hashedUserId.ts | |
+++ b/client/src/composables/hashedUserId.ts | |
@@ -59,6 +59,7 @@ export function useHashedUserId(user?: Ref<AnyUser>) { | |
); | |
async function hashUserId(id: string) { | |
+ console.debug("Hashing user id", id); | |
if (unhashedId !== id) { | |
unhashedId = id; | |
currentHash.value = null; | |
diff --git a/client/src/composables/userLocalStorage.ts b/client/src/composables/userLocalStorage.ts | |
index d81dfda55e..2b1270f34d 100644 | |
--- a/client/src/composables/userLocalStorage.ts | |
+++ b/client/src/composables/userLocalStorage.ts | |
@@ -1,28 +1,86 @@ | |
+// userLocalStorage.ts | |
import { watchImmediate } from "@vueuse/core"; | |
-import { type Ref, ref } from "vue"; | |
+import { type Ref, ref, watch } from "vue"; | |
import { type AnyUser } from "@/api"; | |
import { useHashedUserId } from "./hashedUserId"; | |
import { syncRefToLocalStorage } from "./persistentRef"; | |
+interface PendingChange { | |
+ key: string; | |
+ value: any; // Use any here | |
+ type: "string" | "number" | "boolean" | "object"; | |
+} | |
+ | |
+const pendingChanges: PendingChange[] = []; | |
+ | |
/** | |
* Local storage composable specific to current user. | |
* @param key | |
* @param initialValue | |
*/ | |
-export function useUserLocalStorage<T>(key: string, initialValue: T, user?: Ref<AnyUser>) { | |
+export function useUserLocalStorage<T>(key: string, initialValue: T, user?: Ref<AnyUser>): Ref<T> { | |
+ //return Ref<T> | |
const { hashedUserId } = useHashedUserId(user); | |
- | |
- const refToSync = ref(initialValue); | |
+ const refToSync = ref(initialValue) as Ref<T>; | |
let hasSynced = false; | |
+ // Function to apply pending changes | |
+ const applyPendingChanges = (userId: string) => { | |
+ const changesToApply = pendingChanges.filter((change) => change.key === key); | |
+ if (changesToApply.length > 0) { | |
+ console.debug(`Applying ${changesToApply.length} pending changes for key "${key}"`); | |
+ changesToApply.forEach((change) => { | |
+ // No try-catch is needed when applying to memory (it's needed when parsing) | |
+ // No type checking or casting is needed here! | |
+ refToSync.value = change.value; | |
+ | |
+ //remove item from pending changes | |
+ const index = pendingChanges.indexOf(change); | |
+ if (index > -1) { | |
+ pendingChanges.splice(index, 1); | |
+ } | |
+ }); | |
+ | |
+ // Sync to local storage after applying in-memory changes. | |
+ syncRefToLocalStorage(`${key}-${userId}`, refToSync); | |
+ } | |
+ }; | |
+ | |
+ // Watch for changes to refToSync and store them if hashedUserId is not yet available. | |
+ watch( | |
+ refToSync, | |
+ (newValue) => { | |
+ if (!hashedUserId.value) { | |
+ console.debug(`Queueing change for key "${key}" until user ID is available.`); | |
+ // Check if a change for this key already exists, and update it, or add a new change | |
+ | |
+ const existingChangeIndex = pendingChanges.findIndex((change) => change.key === key); | |
+ const type = typeof newValue as "string" | "number" | "boolean" | "object"; | |
+ if (existingChangeIndex > -1) { | |
+ pendingChanges[existingChangeIndex] = { key, value: newValue, type }; | |
+ } else { | |
+ pendingChanges.push({ key, value: newValue, type }); | |
+ } | |
+ } else if (!hasSynced) { | |
+ //This case handles calls to setItem that might happen *after* hashedUserId is set, | |
+ // but *before* this particular watchImmediate has run. | |
+ syncRefToLocalStorage(`${key}-${hashedUserId.value}`, refToSync); | |
+ } | |
+ }, | |
+ { deep: true } | |
+ ); | |
+ | |
watchImmediate( | |
() => hashedUserId.value, | |
() => { | |
if (hashedUserId.value && !hasSynced) { | |
+ applyPendingChanges(hashedUserId.value); // Apply pending changes first | |
syncRefToLocalStorage(`${key}-${hashedUserId.value}`, refToSync); | |
hasSynced = true; | |
+ } else { | |
+ console.debug("NO USER -- SKIPPING", key, hashedUserId.value); | |
} | |
} | |
); | |
diff --git a/client/src/entry/analysis/router.js b/client/src/entry/analysis/router.js | |
index 7358e84708..f5ca031300 100644 | |
--- a/client/src/entry/analysis/router.js | |
+++ b/client/src/entry/analysis/router.js | |
@@ -54,6 +54,8 @@ import AdminRoutes from "entry/analysis/routes/admin-routes"; | |
import LibraryRoutes from "entry/analysis/routes/library-routes"; | |
import StorageDashboardRoutes from "entry/analysis/routes/storageDashboardRoutes"; | |
import { getAppRoot } from "onload/loadConfig"; | |
+import { useActivityStore } from "stores/activityStore"; | |
+import { useUserStore } from "stores/userStore"; | |
import Vue from "vue"; | |
import VueRouter from "vue-router"; | |
diff --git a/client/src/stores/activityStore.ts b/client/src/stores/activityStore.ts | |
index f7fad52718..b91904aa5c 100644 | |
--- a/client/src/stores/activityStore.ts | |
+++ b/client/src/stores/activityStore.ts | |
@@ -69,7 +69,10 @@ export const useActivityStore = defineScopedStore("activityStore", (scope) => { | |
} | |
function closeSideBar() { | |
+ console.debug("CLOSE SIDEBAR"); | |
toggledSideBar.value = "closed"; | |
+ console.debug("AFTER CLOSE SIDEBAR", isSideBarOpen.value); | |
+ sync(); | |
} | |
function overrideDefaultActivities(activities: Activity[]) { | |
@@ -95,6 +98,7 @@ export const useActivityStore = defineScopedStore("activityStore", (scope) => { | |
* to the user stored activities which are persisted in local cache. | |
*/ | |
const sync = useDebounceFn(() => { | |
+ console.trace("sync"); | |
// create a map of built-in activities | |
const activitiesMap: Record<string, Activity> = {}; | |
@@ -133,8 +137,8 @@ export const useActivityStore = defineScopedStore("activityStore", (scope) => { | |
}); | |
activities.value = newActivities; | |
- | |
// if toggled side-bar does not exist, choose the first option | |
+ console.debug("IN SYNC< SIDEBAR OPEN IS", isSideBarOpen.value, "value is ", toggledSideBar.value); | |
if (isSideBarOpen.value) { | |
const allSideBars = activities.value.flatMap((activity) => { | |
if (activity.panel) { | |
@@ -193,7 +197,8 @@ export const useActivityStore = defineScopedStore("activityStore", (scope) => { | |
watchImmediate( | |
() => hashedUserId.value, | |
- () => { | |
+ (newValue, oldValue) => { | |
+ console.debug("Sync from watchImmediate", oldValue, newValue); | |
sync(); | |
} | |
); | |
diff --git a/client/src/stores/userStore.ts b/client/src/stores/userStore.ts | |
index 4e3499e800..f7f385afd7 100644 | |
--- a/client/src/stores/userStore.ts | |
+++ b/client/src/stores/userStore.ts | |
@@ -68,7 +68,7 @@ export const useUserStore = defineStore("userStore", () => { | |
currentUser.value = user; | |
} | |
- function loadUser(includeHistories = true) { | |
+ function loadUser(includeHistories = true): Promise<void> { | |
if (!loadPromise) { | |
loadPromise = new Promise<void>((resolve, reject) => { | |
(async () => { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment