Skip to content

Commit ae336d4

Browse files
committed
Ensure quota and user store stay in sync after updates
Improves consistency between user and quota usage data by having the user store trigger refreshes of the quota usage store after relevant user updates. Adds logic to detect when a user update should prompt a quota refresh and ensures both stores are updated atomically. Refactors user state management for clarity and correctness, adding methods for explicit user and quota syncing, and updating related helpers and test utilities to use new store methods.
1 parent e282128 commit ae336d4

4 files changed

Lines changed: 62 additions & 13 deletions

File tree

client/src/api/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ export interface AnonymousUser extends AnonymousUserModel {
275275
/** Represents any user, including anonymous users or session-less (null) users.**/
276276
export type AnyUser = RegisteredUser | AnonymousUser | null;
277277

278+
export function toAnyUser(user: UserModel): AnyUser {
279+
if ("email" in user) {
280+
return { ...user, isAnonymous: false } as RegisteredUser;
281+
}
282+
return { ...user, isAnonymous: true } as AnonymousUser;
283+
}
284+
278285
export function isRegisteredUser(user: AnyUser | UserModel): user is RegisteredUser {
279286
return user !== null && "email" in user;
280287
}

client/src/stores/userStore.ts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type AnyUser, isAdminUser, isAnonymousUser, isRegisteredUser, type Regi
55
import { useHashedUserId } from "@/composables/hashedUserId";
66
import { useUserLocalStorageFromHashId } from "@/composables/userLocalStorageFromHashedId";
77
import { useHistoryStore } from "@/stores/historyStore";
8+
import { useQuotaUsageStore } from "@/stores/quotaUsageStore";
89
import {
910
addFavoriteToolQuery,
1011
getCurrentUser,
@@ -47,6 +48,25 @@ export const useUserStore = defineStore("userStore", () => {
4748

4849
let loadPromise: Promise<void> | null = null;
4950

51+
function requestQuotaRefreshForLoadedQuotaStore() {
52+
const quotaUsageStore = useQuotaUsageStore();
53+
if (quotaUsageStore.isLoaded) {
54+
quotaUsageStore.requestRefreshDebounced();
55+
}
56+
}
57+
58+
function shouldRefreshQuotaAfterUserUpdate(previousUser: AnyUser, nextUser: RegisteredUser) {
59+
if (!isRegisteredUser(previousUser)) {
60+
return true;
61+
}
62+
63+
return (
64+
previousUser.total_disk_usage !== nextUser.total_disk_usage ||
65+
previousUser.quota_percent !== nextUser.quota_percent ||
66+
previousUser.quota !== nextUser.quota
67+
);
68+
}
69+
5070
function $reset() {
5171
currentUser.value = null;
5272
currentPreferences.value = null;
@@ -84,21 +104,38 @@ export const useUserStore = defineStore("userStore", () => {
84104
currentUser.value = user;
85105
}
86106

107+
function setUserState(user: AnyUser) {
108+
const previousUser = currentUser.value;
109+
110+
if (isRegisteredUser(user)) {
111+
currentUser.value = user;
112+
currentPreferences.value = processUserPreferences(user);
113+
if (shouldRefreshQuotaAfterUserUpdate(previousUser, user)) {
114+
requestQuotaRefreshForLoadedQuotaStore();
115+
}
116+
} else if (isAnonymousUser(user)) {
117+
currentUser.value = user;
118+
} else if (user === null) {
119+
currentUser.value = null;
120+
}
121+
}
122+
123+
function syncCurrentUser(user: AnyUser) {
124+
setUserState(user);
125+
}
126+
127+
function refreshUser(includeHistories = false) {
128+
loadPromise = null;
129+
return loadUser(includeHistories);
130+
}
131+
87132
function loadUser(includeHistories = true) {
88133
if (!loadPromise) {
89134
loadPromise = new Promise<void>((resolve, reject) => {
90135
(async () => {
91136
try {
92137
const user = await getCurrentUser();
93-
94-
if (isRegisteredUser(user)) {
95-
currentUser.value = user;
96-
currentPreferences.value = processUserPreferences(user);
97-
} else if (isAnonymousUser(user)) {
98-
currentUser.value = user;
99-
} else if (user === null) {
100-
currentUser.value = null;
101-
}
138+
setUserState(user);
102139
if (includeHistories) {
103140
const historyStore = useHistoryStore();
104141
await historyStore.loadHistories();
@@ -190,6 +227,8 @@ export const useUserStore = defineStore("userStore", () => {
190227
historyPanelWidth,
191228
recentTools,
192229
loadUser,
230+
refreshUser,
231+
syncCurrentUser,
193232
matchesCurrentUsername,
194233
setCurrentUser,
195234
setCurrentTheme,

client/src/stores/users/queries.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { GalaxyApi } from "@/api";
1+
import { type AnyUser, GalaxyApi, toAnyUser } from "@/api";
22
import { rethrowSimple } from "@/utils/simple-error";
33

4-
export async function getCurrentUser() {
4+
export async function getCurrentUser(): Promise<AnyUser> {
55
const { data, error } = await GalaxyApi().GET("/api/users/{user_id}", {
66
params: { path: { user_id: "current" } },
77
});
88

99
if (error) {
1010
rethrowSimple(error);
1111
}
12-
return data;
12+
return toAnyUser(data);
1313
}
1414

1515
export async function addFavoriteToolQuery(userId: string, toolId: string) {

client/src/watch/watchHistory.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { useCollectionElementsStore } from "@/stores/collectionElementsStore";
1111
import { useDatasetStore } from "@/stores/datasetStore";
1212
import { useHistoryItemsStore } from "@/stores/historyItemsStore";
1313
import { useHistoryStore } from "@/stores/historyStore";
14+
import { useUserStore } from "@/stores/userStore";
1415
import { loadSet } from "@/utils/setCache";
1516
import { urlData } from "@/utils/url";
1617

@@ -97,7 +98,9 @@ async function _fetchHistoryAndChangedItems(app, { force }) {
9798
historyItemsStore.saveHistoryItems(historyId, payload);
9899
collectionElementsStore.saveCollections(payload);
99100
if (app) {
100-
app.user.loadFromApi(app.user.id || "current");
101+
await app.user.loadFromApi(app.user.id || "current");
102+
const userStore = useUserStore();
103+
userStore.syncCurrentUser(app.user.attributes ?? null);
101104
}
102105
}
103106

0 commit comments

Comments
 (0)