Skip to content

Commit

Permalink
Merge pull request galaxyproject#17853 from jmchilton/storage_managem…
Browse files Browse the repository at this point in the history
…ent_within_history

Enable managing object store usage within a history.
  • Loading branch information
jmchilton authored Apr 3, 2024
2 parents 0d3e8cd + b7ec41f commit d8756c6
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 32 deletions.
2 changes: 1 addition & 1 deletion client/src/api/datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export async function fetchDatasetDetails(params: { id: string }): Promise<Datas

const updateDataset = fetcher.path("/api/datasets/{dataset_id}").method("put").create();

export async function undeleteHistoryDataset(datasetId: string) {
export async function undeleteDataset(datasetId: string) {
const { data } = await updateDataset({
dataset_id: datasetId,
type: "dataset",
Expand Down
12 changes: 3 additions & 9 deletions client/src/components/Common/FilterMenuObjectStore.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script setup lang="ts">
import { storeToRefs } from "pinia";
import { computed, ref, watch } from "vue";
import { useObjectStoreStore } from "@/stores/objectStoreStore";
import { useSelectableObjectStores } from "@/composables/useObjectStores";
import { ValidFilter } from "@/utils/filtering";
import FilterObjectStoreLink from "./FilterObjectStoreLink.vue";
Expand Down Expand Up @@ -40,20 +39,15 @@ watch(
}
);
const store = useObjectStoreStore();
const { selectableObjectStores } = storeToRefs(store);
const hasObjectStores = computed(() => {
return selectableObjectStores.value && selectableObjectStores.value.length > 0;
});
const { selectableObjectStores, hasSelectableObjectStores } = useSelectableObjectStores();
function onChange(value: string | null) {
localValue.value = (value || undefined) as FilterType;
}
</script>

<template>
<div v-if="hasObjectStores">
<div v-if="hasSelectableObjectStores">
<small>Filter by storage source:</small>
<FilterObjectStoreLink :object-stores="selectableObjectStores" :value="localValue" @change="onChange" />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { BCard } from "bootstrap-vue";
import * as d3 from "d3";
import { computed, onMounted, ref, watch } from "vue";
import { computed, nextTick, onMounted, ref, watch } from "vue";
import type { DataValuePoint } from ".";
Expand Down Expand Up @@ -63,8 +63,14 @@ watch(
props.valueFormatter,
],
() => {
clearChart();
renderBarChart();
// make sure v-if to conditionally display the div we're rendering this in
// is available in the DOM before actually doing the rendering. Without
// nextTick you cannot go from empty data -> chart when tweaking filtering
// parameters.
nextTick(() => {
clearChart();
renderBarChart();
});
}
);
Expand Down Expand Up @@ -313,6 +319,7 @@ function setTooltipPosition(mouseX: number, mouseY: number): void {
</slot>
</h3>
</template>
<slot name="options" />
<div v-if="hasData">
<p class="chart-description">{{ description }}</p>
<div class="chart-area">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
<script setup lang="ts">
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BButton, BForm, BFormGroup, BFormSelect, BInputGroup } from "bootstrap-vue";
import { ref } from "vue";
import { useRouter } from "vue-router/composables";
import { useSelectableObjectStores } from "@/composables/useObjectStores";
import { useHistoryStore } from "@/stores/historyStore";
import localize from "@/utils/localization";
import type { DataValuePoint } from "./Charts";
import { fetchHistoryContentsSizeSummary, type ItemSizeSummary } from "./service";
import { buildTopNDatasetsBySizeData, byteFormattingForChart, useDataLoading, useDatasetsToDisplay } from "./util";
import {
buildTopNDatasetsBySizeData,
byteFormattingForChart,
useAdvancedFiltering,
useDataLoading,
useDatasetsToDisplay,
} from "./util";
import BarChart from "./Charts/BarChart.vue";
import OverviewPage from "./OverviewPage.vue";
import RecoverableItemSizeTooltip from "./RecoverableItemSizeTooltip.vue";
import SelectedItemActions from "./SelectedItemActions.vue";
import WarnDeletedDatasets from "./WarnDeletedDatasets.vue";
import FilterObjectStoreLink from "@/components/Common/FilterObjectStoreLink.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
const router = useRouter();
Expand All @@ -38,16 +48,29 @@ const {
} = useDatasetsToDisplay();
const { isLoading, loadDataOnMount } = useDataLoading();
const { isAdvanced, toggleAdvanced, inputGroupClasses, faAngleDoubleDown, faAngleDoubleUp } = useAdvancedFiltering();
const { selectableObjectStores, hasSelectableObjectStores } = useSelectableObjectStores();
loadDataOnMount(async () => {
const objectStore = ref<string | null>(null);
function onChangeObjectStore(value: string | null) {
objectStore.value = value;
reloadDataFromServer();
}
async function reloadDataFromServer() {
const allDatasetsInHistorySizeSummary = await fetchHistoryContentsSizeSummary(
props.historyId,
numberOfDatasetsLimit
numberOfDatasetsLimit,
objectStore.value
);
datasetsSizeSummaryMap.clear();
allDatasetsInHistorySizeSummary.forEach((dataset) => datasetsSizeSummaryMap.set(dataset.id, dataset));
buildGraphsData();
});
}
loadDataOnMount(reloadDataFromServer);
function buildGraphsData() {
const allDatasetsInHistorySizeSummary = Array.from(datasetsSizeSummaryMap.values());
Expand Down Expand Up @@ -124,15 +147,56 @@ function onUndelete(datasetId: string) {
v-bind="byteFormattingForChart">
<template v-slot:title>
<b>{{ localize(`Top ${numberOfDatasetsToDisplay} Datasets by Size`) }}</b>
<b-form-select
v-model="numberOfDatasetsToDisplay"
:options="numberOfDatasetsToDisplayOptions"
:disabled="isLoading"
title="Number of datasets to show"
class="float-right w-auto"
size="sm"
@change="buildGraphsData()">
</b-form-select>
<BInputGroup size="sm" :class="inputGroupClasses">
<BFormSelect
v-if="!isAdvanced"
v-model="numberOfDatasetsToDisplay"
:options="numberOfDatasetsToDisplayOptions"
:disabled="isLoading"
title="Number of histories to show"
size="sm"
@change="buildGraphsData()">
</BFormSelect>
<BButton
v-b-tooltip.hover.bottom.noninteractive
aria-haspopup="true"
size="sm"
title="Toggle Advanced Filtering"
data-description="wide toggle advanced filter"
@click="toggleAdvanced">
<FontAwesomeIcon :icon="isAdvanced ? faAngleDoubleUp : faAngleDoubleDown" />
</BButton>
</BInputGroup>
</template>
<template v-slot:options>
<div v-if="isAdvanced" class="clear-fix">
<BForm>
<BFormGroup
id="input-group-num-histories"
label="Number of histories:"
label-for="input-num-histories"
description="This is the maximum number of histories that will be displayed.">
<BFormSelect
v-model="numberOfDatasetsToDisplay"
:options="numberOfDatasetsToDisplayOptions"
:disabled="isLoading"
title="Number of histories to show"
@change="buildGraphsData()">
</BFormSelect>
</BFormGroup>
<BFormGroup
v-if="hasSelectableObjectStores"
id="input-group-object-store"
label="Storage location:"
label-for="input-object-store"
description="This will constrain history size calculations to a particular object store.">
<FilterObjectStoreLink
:object-stores="selectableObjectStores"
:value="objectStore"
@change="onChangeObjectStore" />
</BFormGroup>
</BForm>
</div>
</template>
<template v-slot:tooltip="{ data }">
<RecoverableItemSizeTooltip
Expand Down
22 changes: 17 additions & 5 deletions client/src/components/User/DiskUsage/Visualizations/service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { datasetsFetcher, purgeDataset, undeleteHistoryDataset } from "@/api/datasets";
import { datasetsFetcher, purgeDataset, undeleteDataset } from "@/api/datasets";
import { archivedHistoriesFetcher, deleteHistory, historiesFetcher, undeleteHistory } from "@/api/histories";

export interface ItemSizeSummary {
Expand Down Expand Up @@ -33,14 +33,26 @@ export async function fetchAllHistoriesSizeSummary(): Promise<ItemSizeSummary[]>
return allHistoriesTakingStorageResponse;
}

export async function fetchHistoryContentsSizeSummary(historyId: string, limit = 5000) {
export async function fetchHistoryContentsSizeSummary(
historyId: string,
limit: number = 5000,
objectStoreId: string | null = null
) {
const q = ["purged", "history_content_type"];
const qv = ["false", "dataset"];

if (objectStoreId) {
q.push("object_store_id");
qv.push(objectStoreId);
}

const response = await datasetsFetcher({
history_id: historyId,
keys: itemSizeSummaryFields,
limit,
order: "size-dsc",
q: ["purged", "history_content_type"],
qv: ["false", "dataset"],
q: q,
qv: qv,
});
return response.data as unknown as ItemSizeSummary[];
}
Expand All @@ -67,7 +79,7 @@ export async function purgeHistoryById(historyId: string): Promise<PurgeableItem
}

export async function undeleteDatasetById(datasetId: string): Promise<ItemSizeSummary> {
const data = await undeleteHistoryDataset(datasetId);
const data = await undeleteDataset(datasetId);
return data as unknown as ItemSizeSummary;
}

Expand Down
26 changes: 25 additions & 1 deletion client/src/components/User/DiskUsage/Visualizations/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { onMounted, ref } from "vue";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faAngleDoubleDown, faAngleDoubleUp } from "@fortawesome/free-solid-svg-icons";
import { computed, onMounted, ref } from "vue";

import { useConfirmDialog } from "@/composables/confirmDialog";
import { useToast } from "@/composables/toast";
Expand All @@ -8,6 +10,8 @@ import type { DataValuePoint } from "./Charts";
import { bytesLabelFormatter, bytesValueFormatter } from "./Charts/formatters";
import { type ItemSizeSummary, purgeDatasetById, undeleteDatasetById } from "./service";

library.add(faAngleDoubleUp, faAngleDoubleDown);

interface DataLoader {
(): Promise<void>;
}
Expand Down Expand Up @@ -117,3 +121,23 @@ export const byteFormattingForChart = {
labelFormatter: bytesLabelFormatter,
valueFormatter: bytesValueFormatter,
};

export function useAdvancedFiltering() {
const isAdvanced = ref<boolean>(false);

function toggleAdvanced() {
isAdvanced.value = !isAdvanced.value;
}

const inputGroupClasses = computed(() => {
return ["float-right", "auto"];
});

return {
faAngleDoubleUp,
faAngleDoubleDown,
isAdvanced,
inputGroupClasses,
toggleAdvanced,
};
}
18 changes: 18 additions & 0 deletions client/src/composables/useObjectStores.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { storeToRefs } from "pinia";
import { computed } from "vue";

import { useObjectStoreStore } from "@/stores/objectStoreStore";

export function useSelectableObjectStores() {
const store = useObjectStoreStore();
const { selectableObjectStores } = storeToRefs(store);

const hasSelectableObjectStores = computed(() => {
return selectableObjectStores.value && selectableObjectStores.value.length > 0;
});

return {
selectableObjectStores,
hasSelectableObjectStores,
};
}

0 comments on commit d8756c6

Please sign in to comment.