@@ -79,23 +95,15 @@ function onCountDownChanged(count: number) {
-
+
Recalculating disk usage... this may take some time, please check back later.
From 7deccad2133b95bda5ab2f90a85045a86b2fb665 Mon Sep 17 00:00:00 2001
From: davelopez <46503462+davelopez@users.noreply.github.com>
Date: Fri, 8 Sep 2023 17:08:30 +0200
Subject: [PATCH 3/5] Load user's histories conditionally
We may want to load the updated user values without reloading histories.
---
.../components/User/DiskUsage/DiskUsageSummary.vue | 3 ++-
client/src/stores/userStore.ts | 12 +++++++-----
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/client/src/components/User/DiskUsage/DiskUsageSummary.vue b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
index ed561346c6f5..ffac1b71b614 100644
--- a/client/src/components/User/DiskUsage/DiskUsageSummary.vue
+++ b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
@@ -44,7 +44,8 @@ watch(
(newValue, oldValue) => {
// Make sure we reload the user when the recalculation is done
if (oldValue && !newValue) {
- userStore.loadUser();
+ const includeHistories = false;
+ userStore.loadUser(includeHistories);
}
}
);
diff --git a/client/src/stores/userStore.ts b/client/src/stores/userStore.ts
index 43dfb82c0b7a..13093688433c 100644
--- a/client/src/stores/userStore.ts
+++ b/client/src/stores/userStore.ts
@@ -57,20 +57,22 @@ export const useUserStore = defineStore("userStore", () => {
currentUser.value = user;
}
- function loadUser() {
+ function loadUser(includeHistories = true) {
if (!loadPromise) {
loadPromise = getCurrentUser()
.then(async (user) => {
- const historyStore = useHistoryStore();
currentUser.value = { ...user, isAnonymous: !user.email };
currentPreferences.value = user?.preferences ?? null;
// TODO: This is a hack to get around the fact that the API returns a string
if (currentPreferences.value?.favorites) {
currentPreferences.value.favorites = JSON.parse(user?.preferences?.favorites ?? { tools: [] });
}
- await historyStore.loadCurrentHistory();
- // load first few histories for user to start pagination
- await historyStore.loadHistories();
+ if (includeHistories) {
+ const historyStore = useHistoryStore();
+ await historyStore.loadCurrentHistory();
+ // load first few histories for user to start pagination
+ await historyStore.loadHistories();
+ }
})
.catch((e) => {
console.error("Failed to load user", e);
From 929c62d93f991959192142b769f9059c7bc778ad Mon Sep 17 00:00:00 2001
From: davelopez <46503462+davelopez@users.noreply.github.com>
Date: Fri, 8 Sep 2023 17:36:15 +0200
Subject: [PATCH 4/5] Display all user's quota sources in dashboard
---
.../src/components/Page/PageDropdown.test.ts | 16 ++++++++--
.../User/DiskUsage/DiskUsageSummary.vue | 30 ++++++++++++-------
.../DiskUsage/Quota/model/QuotaUsage.test.ts | 8 ++---
.../User/DiskUsage/Quota/model/QuotaUsage.ts | 6 ++--
.../User/DiskUsage/Quota/model/index.js | 2 +-
5 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/client/src/components/Page/PageDropdown.test.ts b/client/src/components/Page/PageDropdown.test.ts
index 222f892ed48d..33e0b548d313 100644
--- a/client/src/components/Page/PageDropdown.test.ts
+++ b/client/src/components/Page/PageDropdown.test.ts
@@ -52,7 +52,13 @@ describe("PageDropdown.vue", () => {
pinia: pinia,
});
const userStore = useUserStore();
- userStore.currentUser = { email: "my@email", id: "1", tags_used: [], isAnonymous: false };
+ userStore.currentUser = {
+ email: "my@email",
+ id: "1",
+ tags_used: [],
+ isAnonymous: false,
+ total_disk_usage: 1048576,
+ };
});
it("should show page title", async () => {
@@ -113,7 +119,13 @@ describe("PageDropdown.vue", () => {
},
});
const userStore = useUserStore();
- userStore.currentUser = { email: "my@email", id: "1", tags_used: [], isAnonymous: false };
+ userStore.currentUser = {
+ email: "my@email",
+ id: "1",
+ tags_used: [],
+ isAnonymous: false,
+ total_disk_usage: 1048576,
+ };
wrapper.find(".page-dropdown").trigger("click");
await wrapper.vm.$nextTick();
wrapper.find(".dropdown-item-delete").trigger("click");
diff --git a/client/src/components/User/DiskUsage/DiskUsageSummary.vue b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
index ffac1b71b614..f409ad79228a 100644
--- a/client/src/components/User/DiskUsage/DiskUsageSummary.vue
+++ b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
@@ -1,6 +1,6 @@
diff --git a/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.test.ts b/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.test.ts
index 134aaa510b06..006440faf1a2 100644
--- a/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.test.ts
+++ b/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.test.ts
@@ -1,20 +1,20 @@
-import { DEFAULT_QUOTA_SOURCE_LABEL, QuotaUsage, type QuotaUsageResponse } from "./QuotaUsage";
+import { DEFAULT_QUOTA_SOURCE_LABEL, QuotaUsage, type UserQuotaUsageData } from "./QuotaUsage";
-const RAW_DEFAULT_QUOTA_USAGE: QuotaUsageResponse = {
+const RAW_DEFAULT_QUOTA_USAGE: UserQuotaUsageData = {
quota_source_label: undefined,
quota_bytes: 68468436,
total_disk_usage: 4546654,
quota_percent: 20,
};
-const RAW_LIMITED_SOURCE_QUOTA_USAGE: QuotaUsageResponse = {
+const RAW_LIMITED_SOURCE_QUOTA_USAGE: UserQuotaUsageData = {
quota_source_label: "The source",
quota_bytes: 68468436,
total_disk_usage: 4546654,
quota_percent: 20,
};
-const RAW_UNLIMITED_SOURCE_QUOTA_USAGE: QuotaUsageResponse = {
+const RAW_UNLIMITED_SOURCE_QUOTA_USAGE: UserQuotaUsageData = {
quota_source_label: "The unlimited source",
quota_bytes: undefined,
total_disk_usage: 4546654,
diff --git a/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.ts b/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.ts
index b34eeb57f10c..9f0c2577bf11 100644
--- a/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.ts
+++ b/client/src/components/User/DiskUsage/Quota/model/QuotaUsage.ts
@@ -3,15 +3,15 @@ import { bytesToString } from "@/utils/utils";
export const DEFAULT_QUOTA_SOURCE_LABEL = "Default";
-type QuotaUsageResponse = components["schemas"]["UserQuotaUsage"];
+export type UserQuotaUsageData = components["schemas"]["UserQuotaUsage"];
/**
* Contains information about quota usage for a particular ObjectStore.
*/
export class QuotaUsage {
- private _data: QuotaUsageResponse;
+ private _data: UserQuotaUsageData;
- constructor(data: QuotaUsageResponse) {
+ constructor(data: UserQuotaUsageData) {
this._data = data;
}
diff --git a/client/src/components/User/DiskUsage/Quota/model/index.js b/client/src/components/User/DiskUsage/Quota/model/index.js
index 43c68fd60b0b..c5818f3a191e 100644
--- a/client/src/components/User/DiskUsage/Quota/model/index.js
+++ b/client/src/components/User/DiskUsage/Quota/model/index.js
@@ -1 +1 @@
-export { QuotaUsage } from "./QuotaUsage";
+export { QuotaUsage, UserQuotaUsageData } from "./QuotaUsage";
From 8be06f05e0f70e8431d859ae82b8bbedd9f68a99 Mon Sep 17 00:00:00 2001
From: davelopez <46503462+davelopez@users.noreply.github.com>
Date: Fri, 8 Sep 2023 18:47:25 +0200
Subject: [PATCH 5/5] Increase test coverage for DiskUsageSummary
---
.../User/DiskUsage/DiskUsageSummary.test.ts | 63 ++++++++++++++++++-
.../User/DiskUsage/DiskUsageSummary.vue | 3 +-
2 files changed, 62 insertions(+), 4 deletions(-)
diff --git a/client/src/components/User/DiskUsage/DiskUsageSummary.test.ts b/client/src/components/User/DiskUsage/DiskUsageSummary.test.ts
index 40508d6323a5..f6f657de91d1 100644
--- a/client/src/components/User/DiskUsage/DiskUsageSummary.test.ts
+++ b/client/src/components/User/DiskUsage/DiskUsageSummary.test.ts
@@ -4,11 +4,15 @@ import { createPinia } from "pinia";
import { getLocalVue } from "tests/jest/helpers";
import { mockFetcher } from "@/schema/__mocks__";
+import { getCurrentUser } from "@/stores/users/queries";
import { useUserStore } from "@/stores/userStore";
+import { UserQuotaUsageData } from "./Quota/model";
+
import DiskUsageSummary from "./DiskUsageSummary.vue";
jest.mock("@/schema");
+jest.mock("@/stores/users/queries");
const localVue = getLocalVue();
@@ -20,17 +24,38 @@ const fakeUserWithQuota = {
email: "fakeUserEmail",
tags_used: [],
isAnonymous: false,
- total_disk_usage: 1054068,
- quota_bytes: 1000000000,
- quota_percent: 0.1,
+ total_disk_usage: 1048576,
+ quota_bytes: 104857600,
+ quota_percent: 1,
quota_source_label: "Default",
};
+// TODO: Replace this with a mockFetcher when #16608 is merged
+const mockGetCurrentUser = getCurrentUser as jest.Mock;
+mockGetCurrentUser.mockImplementation(() => Promise.resolve(fakeUserWithQuota));
+
+const fakeQuotaUsages: UserQuotaUsageData[] = [
+ {
+ quota_source_label: "Default",
+ quota_bytes: 104857600,
+ total_disk_usage: 1048576,
+ },
+];
+
+const fakeTaskId = "fakeTaskId";
+
async function mountDiskUsageSummaryWrapper(enableQuotas: boolean) {
mockFetcher
.path("/api/configuration")
.method("get")
.mock({ data: { enable_quotas: enableQuotas } });
+ mockFetcher.path("/api/users/{user_id}/usage").method("get").mock({ data: fakeQuotaUsages });
+ mockFetcher
+ .path("/api/users/current/recalculate_disk_usage")
+ .method("put")
+ .mock({ status: 200, data: { id: fakeTaskId } });
+ mockFetcher.path("/api/tasks/{task_id}/state").method("get").mock({ data: "SUCCESS" });
+
const pinia = createPinia();
const wrapper = mount(DiskUsageSummary, {
localVue,
@@ -58,4 +83,36 @@ describe("DiskUsageSummary.vue", () => {
const quotaUsages = wrapper.findAll(quotaUsageClassSelector);
expect(quotaUsages.length).toBe(1);
});
+
+ it("should display the correct quota usage", async () => {
+ const enableQuotasInConfig = true;
+ const wrapper = await mountDiskUsageSummaryWrapper(enableQuotasInConfig);
+ const quotaUsage = wrapper.find(quotaUsageClassSelector);
+ expect(quotaUsage.text()).toContain("1 MB");
+ });
+
+ it("should refresh the quota usage when the user clicks the refresh button", async () => {
+ const enableQuotasInConfig = true;
+ const wrapper = await mountDiskUsageSummaryWrapper(enableQuotasInConfig);
+ const quotaUsage = wrapper.find(quotaUsageClassSelector);
+ expect(quotaUsage.text()).toContain("1 MB");
+ const updatedFakeQuotaUsages: UserQuotaUsageData[] = [
+ {
+ quota_source_label: "Default",
+ quota_bytes: 104857600,
+ total_disk_usage: 2097152,
+ },
+ ];
+ mockFetcher.path("/api/users/{user_id}/usage").method("get").mock({ data: updatedFakeQuotaUsages });
+ await wrapper.find("#refresh-disk-usage").trigger("click");
+ await flushPromises();
+ const refreshingAlert = wrapper.find(".refreshing-alert");
+ expect(refreshingAlert.exists()).toBe(true);
+ // Make sure the refresh has finished before checking the quota usage
+ await flushPromises();
+ await flushPromises();
+ // The refreshing alert should disappear and the quota usage should be updated
+ expect(refreshingAlert.exists()).toBe(false);
+ expect(quotaUsage.text()).toContain("2 MB");
+ });
});
diff --git a/client/src/components/User/DiskUsage/DiskUsageSummary.vue b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
index f409ad79228a..2aca40bb11e8 100644
--- a/client/src/components/User/DiskUsage/DiskUsageSummary.vue
+++ b/client/src/components/User/DiskUsage/DiskUsageSummary.vue
@@ -105,6 +105,7 @@ onMounted(async () => {
-
+
Recalculating disk usage... this may take some time, please check back later.