Skip to content

Commit

Permalink
implement preferred object store id
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Jun 28, 2022
1 parent 6e97787 commit 5aafbd1
Show file tree
Hide file tree
Showing 51 changed files with 2,453 additions and 118 deletions.
165 changes: 110 additions & 55 deletions client/src/components/History/CurrentHistory/HistoryCounter.vue
Original file line number Diff line number Diff line change
@@ -1,67 +1,112 @@
<template>
<div class="history-size my-1 d-flex justify-content-between">
<b-button
v-b-tooltip.hover
title="Access Dashboard"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="onDashboard">
<icon icon="database" />
<span>{{ history.size | niceFileSize }}</span>
</b-button>
<b-button-group>
<b-button
v-b-tooltip.hover
title="Show active"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('')">
<span class="fa fa-map-marker" />
<span>{{ history.contents_active.active }}</span>
</b-button>
<b-button
v-if="history.contents_active.deleted"
v-b-tooltip.hover
title="Show deleted"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('deleted:true')">
<icon icon="trash" />
<span>{{ history.contents_active.deleted }}</span>
</b-button>
<b-button
v-if="history.contents_active.hidden"
v-b-tooltip.hover
title="Show hidden"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('visible:false')">
<icon icon="eye-slash" />
<span>{{ history.contents_active.hidden }}</span>
</b-button>
<b-button
v-b-tooltip.hover
:title="'Last refreshed ' + diffToNow"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="reloadContents()">
<span :class="reloadButtonCls" />
</b-button>
</b-button-group>
</div>
<ConfigProvider v-slot="{ config }">
<CurrentUser v-slot="{ user }">
<div class="history-size my-1 d-flex justify-content-between">
<b-button
v-if="config.object_store_allows_id_selection"
:id="`history-storage-${history.id}`"
v-b-tooltip.hover
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="showPreferredObjectStoreModal = true">
<icon icon="database" />
<span>{{ history.size | niceFileSize }}</span>
</b-button>
<b-button
v-else
v-b-tooltip.hover
title="Access Dashboard"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="onDashboard">
<icon icon="database" />
<span>{{ history.size | niceFileSize }}</span>
</b-button>
<HistoryTargetPreferredObjectStorePopover
:history-id="history.id"
:history-preferred-object-store-id="historyPreferredObjectStoreId"
:user="user">
</HistoryTargetPreferredObjectStorePopover>
<b-button-group>
<b-button
v-b-tooltip.hover
title="Show active"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('')">
<span class="fa fa-map-marker" />
<span>{{ history.contents_active.active }}</span>
</b-button>
<b-button
v-if="history.contents_active.deleted"
v-b-tooltip.hover
title="Show deleted"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('deleted:true')">
<icon icon="trash" />
<span>{{ history.contents_active.deleted }}</span>
</b-button>
<b-button
v-if="history.contents_active.hidden"
v-b-tooltip.hover
title="Show hidden"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="setFilter('visible:false')">
<icon icon="eye-slash" />
<span>{{ history.contents_active.hidden }}</span>
</b-button>
<b-button
v-b-tooltip.hover
:title="'Last refreshed ' + diffToNow"
variant="link"
size="sm"
class="rounded-0 text-decoration-none"
@click="reloadContents()">
<span :class="reloadButtonCls" />
</b-button>
</b-button-group>
<b-modal
title="History Preferred Object Store"
v-model="showPreferredObjectStoreModal"
modal-class="history-preferred-object-store-modal"
title-tag="h3"
size="sm"
hide-footer>
<HistorySelectPreferredObjectStore
:user-preferred-object-store-id="user.preferred_object_store_id"
:history="history"
:root="root"
@updated="onUpdatePreferredObjectStoreId" />
</b-modal>
</div>
</CurrentUser>
</ConfigProvider>
</template>

<script>
import { backboneRoute } from "components/plugins/legacyNavigation";
import prettyBytes from "pretty-bytes";
import { formatDistanceToNowStrict } from "date-fns";
import ConfigProvider from "components/providers/ConfigProvider";
import CurrentUser from "components/providers/CurrentUser";
import HistorySelectPreferredObjectStore from "./HistorySelectPreferredObjectStore";
import HistoryTargetPreferredObjectStorePopover from "./HistoryTargetPreferredObjectStorePopover";
import { getAppRoot } from "onload/loadConfig";
export default {
components: {
ConfigProvider,
CurrentUser,
HistoryTargetPreferredObjectStorePopover,
HistorySelectPreferredObjectStore,
},
filters: {
niceFileSize(rawSize = 0) {
return prettyBytes(rawSize);
Expand All @@ -75,6 +120,9 @@ export default {
return {
diffToNow: 0,
reloadButtonCls: "fa fa-sync",
showPreferredObjectStoreModal: false,
historyPreferredObjectStoreId: this.history.preferred_object_store_id,
root: getAppRoot(),
};
},
mounted() {
Expand All @@ -99,6 +147,13 @@ export default {
this.reloadButtonCls = "fa fa-sync";
}, 1000);
},
onUpdatePreferredObjectStoreId(preferredObjectStoreId) {
this.showPreferredObjectStoreModal = false;
// ideally this would be pushed back to the history object somehow
// and tracked there... but for now this is only component using
// this information.
this.historyPreferredObjectStoreId = preferredObjectStoreId;
},
},
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { mount } from "@vue/test-utils";
import { getLocalVue } from "jest/helpers";
import HistorySelectPreferredObjectStore from "./HistorySelectPreferredObjectStore";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import flushPromises from "flush-promises";

const localVue = getLocalVue(true);

const TEST_ROOT = "/";
const TEST_HISTORY_ID = "myTestHistoryId";

const TEST_HISTORY = {
id: TEST_HISTORY_ID,
preferred_object_store_id: null,
};

function mountComponent() {
const wrapper = mount(HistorySelectPreferredObjectStore, {
propsData: { userPreferredObjectStoreId: null, history: TEST_HISTORY, root: TEST_ROOT },
localVue,
});
return wrapper;
}

import { ROOT_COMPONENT } from "utils/navigation";

const OBJECT_STORES = [
{ object_store_id: "object_store_1", badges: [], quota: { enabled: false } },
{ object_store_id: "object_store_2", badges: [], quota: { enabled: false } },
];

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

beforeEach(async () => {
axiosMock = new MockAdapter(axios);
axiosMock.onGet("/api/object_store?selectable=true").reply(200, OBJECT_STORES);
});

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

it("updates object store to default on selection null", async () => {
const wrapper = mountComponent();
await flushPromises();
const els = wrapper.findAll(ROOT_COMPONENT.preferences.object_store_selection.option_buttons.selector);
expect(els.length).toBe(3);
const galaxyDefaultOption = wrapper.find(
ROOT_COMPONENT.preferences.object_store_selection.option_button({ object_store_id: "__null__" }).selector
);
expect(galaxyDefaultOption.exists()).toBeTruthy();
axiosMock
.onPut(`/api/histories/${TEST_HISTORY_ID}`, expect.objectContaining({ preferred_object_store_id: null }))
.reply(202);
await galaxyDefaultOption.trigger("click");
await flushPromises();
const errorEl = wrapper.find(".object-store-selection-error");
expect(errorEl.exists()).toBeFalsy();
const emitted = wrapper.emitted();
expect(emitted["updated"][0][0]).toEqual(null);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<SelectObjectStore
:root="root"
:parent-error="error"
:for-what="newDatasetsDescription"
:selected-object-store-id="selectedObjectStoreId"
:default-option-title="defaultOptionTitle"
:default-option-description="defaultOptionDescription"
@onSubmit="handleSubmit" />
</template>

<script>
import axios from "axios";
import SelectObjectStore from "components/ObjectStore/SelectObjectStore";
import { errorMessageAsString } from "utils/simple-error";
export default {
components: {
SelectObjectStore,
},
props: {
userPreferredObjectStoreId: {
type: String,
default: null,
},
history: {
type: Object,
required: true,
},
root: {
type: String,
required: true,
},
},
data() {
const selectedObjectStoreId = this.history.preferred_object_store_id;
return {
error: null,
selectedObjectStoreId: selectedObjectStoreId,
newDatasetsDescription: "New dataset outputs from tools and workflows executed in this history",
popoverPlacement: "left",
galaxySelectionDefalutTitle: "Use Galaxy Defaults",
galaxySelectionDefalutDescription:
"Selecting this will reset Galaxy to default behaviors configured by your Galaxy administrator.",
userSelectionDefalutTitle: "Use Your User Preference Defaults",
userSelectionDefalutDescription:
"Selecting this will cause the history to not set a default and to fallback to your user preference defined default.",
};
},
computed: {
defaultOptionTitle() {
if (this.userPreferredObjectStoreId) {
return this.userSelectionDefalutTitle;
} else {
return this.galaxySelectionDefalutTitle;
}
},
defaultOptionDescription() {
if (this.userPreferredObjectStoreId) {
return this.userSelectionDefalutDescription;
} else {
return this.galaxySelectionDefalutDescription;
}
},
},
methods: {
async handleSubmit(preferredObjectStoreId) {
const payload = { preferred_object_store_id: preferredObjectStoreId };
try {
await axios.put(`${this.root}api/histories/${this.history.id}`, payload);
} catch (e) {
this.error = errorMessageAsString(e);
}
this.selectedObjectStoreId = preferredObjectStoreId;
this.$emit("updated", preferredObjectStoreId);
},
},
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<b-popover :target="`history-storage-${historyId}`" triggers="hover" placement="bottomleft">
<template v-slot:title>Preferred Target Object Store</template>
<p class="history-preferred-object-store-inherited" v-if="historyPreferredObjectStoreId">
This target object store has been set at the history level.
</p>
<p class="history-preferred-object-store-not-inherited" v-else>
This target object store has been inherited from your user preferences (set in User -> Preferences ->
Preferred Object Store). If that option is updated, this history will target that new default.
</p>
<ShowSelectedObjectStore
v-if="preferredObjectStoreId"
:preferred-object-store-id="preferredObjectStoreId"
for-what="Galaxy will default to storing this history's datasets in "></ShowSelectedObjectStore>
<div v-localize>
Change this preference object store target by clicking on the storage button in the history panel.
</div>
</b-popover>
</template>

<script>
import ShowSelectedObjectStore from "components/ObjectStore/ShowSelectedObjectStore";
export default {
components: {
ShowSelectedObjectStore,
},
props: {
historyId: {
type: String,
required: true,
},
historyPreferredObjectStoreId: {
type: String,
},
user: { type: Object, required: true },
},
computed: {
preferredObjectStoreId() {
let id = this.historyPreferredObjectStoreId;
if (!id) {
id = this.user.preferred_object_store_id;
}
return id;
},
},
};
</script>
Loading

0 comments on commit 5aafbd1

Please sign in to comment.