Skip to content

Commit

Permalink
Merge pull request #17436 from jmchilton/modernize_storage
Browse files Browse the repository at this point in the history
Modernize bits and pieces of storage display
  • Loading branch information
martenson authored Feb 14, 2024
2 parents 2b29fc8 + d977ef1 commit 8c52b92
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 118 deletions.
2 changes: 2 additions & 0 deletions client/src/api/datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export async function getDatasets(options: GetDatasetsOptions = {}) {

export const fetchDataset = fetcher.path("/api/datasets/{dataset_id}").method("get").create();

export const fetchDatasetStorage = fetcher.path("/api/datasets/{dataset_id}/storage").method("get").create();

export async function fetchDatasetDetails(params: { id: string }): Promise<DatasetDetails> {
const { data } = await fetchDataset({ dataset_id: params.id, view: "detailed" });
// We know that the server will return a DatasetDetails object because of the view parameter
Expand Down
5 changes: 5 additions & 0 deletions client/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export type DatasetSummary = components["schemas"]["HDASummary"];
*/
export type DatasetDetails = components["schemas"]["HDADetailed"];

/**
* Contains storage (object store, quota, etc..) details for a dataset.
*/
export type DatasetStorageDetails = components["schemas"]["DatasetStorageDetails"];

/**
* Represents a HistoryDatasetAssociation with either summary or detailed information.
*/
Expand Down
3 changes: 2 additions & 1 deletion client/src/api/schema/__mocks__/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ function getMockReturn(path: Path, method: Method, args: any[]) {
}
}

return null;
// if no mock has been setup, never resolve API request
return new Promise(() => {});
}

function setMockReturn(path: Path | RegExp, method: Method, value: any) {

Check warning on line 55 in client/src/api/schema/__mocks__/fetcher.ts

View workflow job for this annotation

GitHub Actions / client-unit-test (18)

Unexpected any. Specify a different type
Expand Down
24 changes: 17 additions & 7 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2925,6 +2925,19 @@ export interface components {
private: boolean;
quota: components["schemas"]["QuotaModel"];
};
/** ConcreteObjectStoreQuotaSourceDetails */
ConcreteObjectStoreQuotaSourceDetails: {
/**
* Enabled
* @description Whether the object store tracks quota on the data (independent of Galaxy's configuration)
*/
enabled: boolean;
/**
* Source
* @description The quota source label corresponding to the object store the dataset is stored in (or would be stored in)
*/
source: string | null;
};
/** ContentsObject */
ContentsObject: {
/**
Expand Down Expand Up @@ -3775,9 +3788,9 @@ export interface components {
DatasetStorageDetails: {
/**
* Badges
* @description A mapping of object store labels to badges describing object store properties.
* @description A list of badges describing object store properties for concrete object store dataset is stored in.
*/
badges: Record<string, never>[];
badges: components["schemas"]["BadgeDict"][];
/**
* Dataset State
* @description The model state of the supplied dataset instance.
Expand Down Expand Up @@ -3808,11 +3821,8 @@ export interface components {
* @description The percentage indicating how full the store is.
*/
percent_used: number | null;
/**
* Quota
* @description Information about quota sources around dataset storage.
*/
quota: Record<string, never>;
/** @description Information about quota sources around dataset storage. */
quota: components["schemas"]["ConcreteObjectStoreQuotaSourceDetails"];
/**
* Shareable
* @description Is this dataset shareable.
Expand Down
29 changes: 12 additions & 17 deletions client/src/components/Dataset/DatasetStorage/DatasetStorage.test.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import { shallowMount } from "@vue/test-utils";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import flushPromises from "flush-promises";
import { getLocalVue } from "tests/jest/helpers";

import { mockFetcher } from "@/api/schema/__mocks__";

import DatasetStorage from "./DatasetStorage";

jest.mock("@/api/schema");

const localVue = getLocalVue();

const TEST_STORAGE_API_RESPONSE_WITHOUT_ID = {
object_store_id: null,
private: false,
};
const TEST_DATASET_ID = "1";
const TEST_STORAGE_URL = `/api/datasets/${TEST_DATASET_ID}/storage`;
const STORAGE_FETCH_URL = "/api/datasets/{dataset_id}/storage";
const TEST_ERROR_MESSAGE = "Opps all errors.";

describe("DatasetStorage.vue", () => {
let axiosMock;
let wrapper;

beforeEach(async () => {
axiosMock = new MockAdapter(axios);
});

function mount() {
wrapper = shallowMount(DatasetStorage, {
propsData: { datasetId: TEST_DATASET_ID },
Expand All @@ -32,7 +29,7 @@ describe("DatasetStorage.vue", () => {
}

async function mountWithResponse(response) {
axiosMock.onGet(TEST_STORAGE_URL).reply(200, response);
mockFetcher.path(STORAGE_FETCH_URL).method("get").mock({ data: response });
mount();
await flushPromises();
}
Expand All @@ -45,9 +42,12 @@ describe("DatasetStorage.vue", () => {
});

it("test error rendering...", async () => {
axiosMock.onGet(TEST_STORAGE_URL).reply(400, {
err_msg: TEST_ERROR_MESSAGE,
});
mockFetcher
.path(STORAGE_FETCH_URL)
.method("get")
.mock(() => {
throw Error(TEST_ERROR_MESSAGE);
});
mount();
await flushPromises();
expect(wrapper.findAll(".error").length).toBe(1);
Expand All @@ -59,10 +59,5 @@ describe("DatasetStorage.vue", () => {
await mountWithResponse(TEST_STORAGE_API_RESPONSE_WITHOUT_ID);
expect(wrapper.findAll("loadingspan-stub").length).toBe(0);
expect(wrapper.findAll("describeobjectstore-stub").length).toBe(1);
expect(wrapper.vm.storageInfo.private).toEqual(false);
});

afterEach(() => {
axiosMock.restore();
});
});
129 changes: 60 additions & 69 deletions client/src/components/Dataset/DatasetStorage/DatasetStorage.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,63 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { DatasetStorageDetails } from "@/api";
import { fetchDatasetStorage } from "@/api/datasets";
import { errorMessageAsString } from "@/utils/simple-error";
import LoadingSpan from "@/components/LoadingSpan.vue";
import DescribeObjectStore from "@/components/ObjectStore/DescribeObjectStore.vue";
interface DatasetStorageProps {
datasetId: string;
datasetType?: "hda" | "ldda";
includeTitle?: boolean;
}
const props = withDefaults(defineProps<DatasetStorageProps>(), {
datasetType: "hda",
includeTitle: true,
});
const storageInfo = ref<DatasetStorageDetails | null>(null);
const errorMessage = ref<string | null>(null);
const discarded = computed(() => {
return storageInfo.value?.dataset_state == "discarded";
});
const deferred = computed(() => {
return storageInfo.value?.dataset_state == "deferred";
});
const sourceUri = computed(() => {
const sources = storageInfo.value?.sources;
if (!sources) {
return null;
}
const rootSources = sources.filter((source) => !source.extra_files_path);
if (rootSources.length == 0) {
return null;
}
return rootSources[0]?.source_uri;
});
watch(
props,
async () => {
const datasetId = props.datasetId;
const datasetType = props.datasetType;
try {
const response = await fetchDatasetStorage({ dataset_id: datasetId, hda_ldda: datasetType });
storageInfo.value = response.data;
} catch (error) {
errorMessage.value = errorMessageAsString(error);
}
},
{ immediate: true }
);
</script>

<template>
<div>
<h2 v-if="includeTitle" class="h-md">Dataset Storage</h2>
Expand All @@ -20,72 +80,3 @@
</div>
</div>
</template>

<script>
import axios from "axios";
import LoadingSpan from "components/LoadingSpan";
import DescribeObjectStore from "components/ObjectStore/DescribeObjectStore";
import { getAppRoot } from "onload/loadConfig";
import { errorMessageAsString } from "utils/simple-error";
export default {
components: {
DescribeObjectStore,
LoadingSpan,
},
props: {
datasetId: {
type: String,
},
datasetType: {
type: String,
default: "hda",
},
includeTitle: {
type: Boolean,
default: true,
},
},
data() {
return {
storageInfo: null,
errorMessage: null,
};
},
computed: {
discarded() {
return this.storageInfo.dataset_state == "discarded";
},
deferred() {
return this.storageInfo.dataset_state == "deferred";
},
sourceUri() {
const sources = this.storageInfo.sources;
if (!sources) {
return null;
}
const rootSources = sources.filter((source) => !source.extra_files_path);
if (rootSources.length == 0) {
return null;
}
return rootSources[0].source_uri;
},
},
created() {
const datasetId = this.datasetId;
const datasetType = this.datasetType;
axios
.get(`${getAppRoot()}api/datasets/${datasetId}/storage`, { hda_ldda: datasetType })
.then(this.handleResponse)
.catch((errorMessage) => {
this.errorMessage = errorMessageAsString(errorMessage);
});
},
methods: {
handleResponse(response) {
const storageInfo = response.data;
this.storageInfo = storageInfo;
},
},
};
</script>
3 changes: 2 additions & 1 deletion client/src/components/HistoryExport/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useFileSources } from "@/composables/fileSources";
import ToLink from "./ToLink.vue";
import ToRemoteFile from "./ToRemoteFile.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
const { isLoading: initializingFileSources, hasWritable: hasWritableFileSources } = useFileSources();
Expand All @@ -18,7 +19,7 @@ const props = defineProps<ExportHistoryProps>();
<span class="history-export-component">
<h1 class="h-lg">Export history archive</h1>
<span v-if="initializingFileSources">
<loading-span message="Loading file sources configuration from Galaxy server." />
<LoadingSpan message="Loading file sources configuration from Galaxy server." />
</span>
<span v-else-if="hasWritableFileSources">
<BCard no-body>
Expand Down
1 change: 1 addition & 0 deletions client/src/components/LoadingSpan.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
</template>
<script>
export default {
name: "LoadingSpan",
props: {
classes: {
type: String,
Expand Down
6 changes: 6 additions & 0 deletions client/src/components/ObjectStore/DescribeObjectStore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ defineExpose({
});
</script>

<script lang="ts">
export default {
name: "DescribeObjectStore",
};
</script>

<template>
<div>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ describe("ShowSelectedObjectStore", () => {
wrapper = mount(ShowSelectedObjectStore, {
propsData: { preferredObjectStoreId: TEST_OBJECT_ID, forWhat: "Data goes into..." },
localVue,
stubs: {
LoadingSpan: true,
DescribeObjectStore: true,
},
});
let loadingEl = wrapper.findComponent(LoadingSpan);
expect(loadingEl.exists()).toBeTruthy();
Expand Down
14 changes: 1 addition & 13 deletions client/src/components/User/DiskUsage/DiskUsageSummary.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { mount } from "@vue/test-utils";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import flushPromises from "flush-promises";
import { createPinia } from "pinia";
import { getLocalVue } from "tests/jest/helpers";
Expand Down Expand Up @@ -69,16 +67,6 @@ async function mountDiskUsageSummaryWrapper(enableQuotas: boolean) {
}

describe("DiskUsageSummary.vue", () => {
let axiosMock: MockAdapter;

beforeEach(async () => {
axiosMock = new MockAdapter(axios);
});

afterEach(async () => {
axiosMock.reset();
});

it("should display basic disk usage summary if quotas are NOT enabled", async () => {
const enableQuotasInConfig = false;
const wrapper = await mountDiskUsageSummaryWrapper(enableQuotasInConfig);
Expand Down Expand Up @@ -115,7 +103,7 @@ describe("DiskUsageSummary.vue", () => {
},
];
mockFetcher.path("/api/users/{user_id}/usage").method("get").mock({ data: updatedFakeQuotaUsages });
axiosMock.onGet(`/api/tasks/${FAKE_TASK_ID}/state`).reply(200, "SUCCESS");
mockFetcher.path("/api/tasks/{task_id}/state").method("get").mock({ data: "SUCCESS" });
const refreshButton = wrapper.find("#refresh-disk-usage");
await refreshButton.trigger("click");
const refreshingAlert = wrapper.find(".refreshing-alert");
Expand Down
Loading

0 comments on commit 8c52b92

Please sign in to comment.