Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 23.2 into 24.0 #17644

Merged
merged 9 commits into from
Mar 8, 2024
100 changes: 100 additions & 0 deletions client/src/components/History/SwitchToHistoryLink.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { createTestingPinia } from "@pinia/testing";
import { getLocalVue } from "@tests/jest/helpers";
import { shallowMount } from "@vue/test-utils";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import flushPromises from "flush-promises";

import { type HistorySummary } from "@/api";

import SwitchToHistoryLink from "./SwitchToHistoryLink.vue";

const localVue = getLocalVue(true);

const selectors = {
historyLink: ".history-link",
} as const;

function mountSwitchToHistoryLinkForHistory(history: HistorySummary) {
const pinia = createTestingPinia();

const axiosMock = new MockAdapter(axios);
axiosMock.onGet(`/api/histories/${history.id}`).reply(200, history);

const wrapper = shallowMount(SwitchToHistoryLink as object, {
propsData: {
historyId: history.id,
},
localVue,
pinia,
stubs: {
FontAwesomeIcon: true,
},
});
return wrapper;
}

async function expectOptionForHistory(option: string, history: HistorySummary) {
const wrapper = mountSwitchToHistoryLinkForHistory(history);

// Wait for the history to be loaded
await flushPromises();

expect(wrapper.html()).toContain(option);
expect(wrapper.text()).toContain(history.name);
}

describe("SwitchToHistoryLink", () => {
it("loads the history information from the store", async () => {
const history = {
id: "history-id-to-load",
name: "History Name",
deleted: false,
archived: false,
purged: false,
} as HistorySummary;
const wrapper = mountSwitchToHistoryLinkForHistory(history);

expect(wrapper.find(selectors.historyLink).exists()).toBe(false);
expect(wrapper.html()).toContain("Loading");

// Wait for the history to be loaded
await flushPromises();

expect(wrapper.find(selectors.historyLink).exists()).toBe(true);
expect(wrapper.text()).toContain(history.name);
});

it("should display the Switch option when the history can be switched to", async () => {
const history = {
id: "active-history-id",
name: "History Active",
deleted: false,
purged: false,
archived: false,
} as HistorySummary;
await expectOptionForHistory("Switch", history);
});

it("should display the View option when the history is purged", async () => {
const history = {
id: "purged-history-id",
name: "History Purged",
deleted: false,
purged: true,
archived: false,
} as HistorySummary;
await expectOptionForHistory("View", history);
});

it("should display the View option when the history is archived", async () => {
const history = {
id: "archived-history-id",
name: "History Archived",
deleted: false,
purged: false,
archived: true,
} as HistorySummary;
await expectOptionForHistory("View", history);
});
});
66 changes: 66 additions & 0 deletions client/src/components/History/SwitchToHistoryLink.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script setup lang="ts">
import { library } from "@fortawesome/fontawesome-svg-core";
import { faArchive, faBurn } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BLink } from "bootstrap-vue";
import { computed } from "vue";
import { useRouter } from "vue-router/composables";

import { HistorySummary } from "@/api";
import { useHistoryStore } from "@/stores/historyStore";

import LoadingSpan from "@/components/LoadingSpan.vue";

library.add(faArchive, faBurn);

const router = useRouter();
const historyStore = useHistoryStore();

interface Props {
historyId: string;
}

const props = defineProps<Props>();

const history = computed(() => historyStore.getHistoryById(props.historyId));

const canSwitch = computed(() => !!history.value && !history.value.archived && !history.value.purged);

const actionText = computed(() => (canSwitch.value ? "Switch to" : "View in new tab"));

function onClick(history: HistorySummary) {
if (canSwitch.value) {
historyStore.setCurrentHistory(history.id);
return;
}
viewHistoryInNewTab(history);
}

function viewHistoryInNewTab(history: HistorySummary) {
const routeData = router.resolve(`/histories/view?id=${history.id}`);
window.open(routeData.href, "_blank");
}
</script>

<template>
<div>
<LoadingSpan v-if="!history" />
<div v-else v-b-tooltip.hover.top.html :title="`<b>${actionText}</b><br>${history.name}`" class="history-link">
<BLink class="truncate" href="#" @click.stop="onClick(history)">
{{ history.name }}
</BLink>

<FontAwesomeIcon v-if="history.purged" :icon="faBurn" fixed-width />
<FontAwesomeIcon v-else-if="history.archived" :icon="faArchive" fixed-width />
</div>
</div>
</template>

<style scoped>
.history-link {
display: flex;
gap: 1px;
align-items: center;
justify-content: space-between;
}
</style>
9 changes: 1 addition & 8 deletions client/src/components/Workflow/InvocationsList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ describe("InvocationsList.vue", () => {
const row = rows[0];
const columns = row.findAll("td");
expect(columns.at(1).text()).toBe("workflow name");
expect(columns.at(2).text()).toBe("history name");
expect(columns.at(2).text()).toBe("Loading..."); // Checking the actual name will be tested in its own component
expect(columns.at(3).text()).toBe(
formatDistanceToNow(parseISO(`${mockInvocationData.create_time}Z`), { addSuffix: true })
);
Expand All @@ -188,13 +188,6 @@ describe("InvocationsList.vue", () => {
expect(rows.length).toBe(1);
});

it("calls switchHistory", async () => {
const mockMethod = jest.fn();
wrapper.vm.switchHistory = mockMethod;
await wrapper.find("#switch-to-history").trigger("click");
expect(mockMethod).toHaveBeenCalled();
});

it("check run button", async () => {
const runButton = await wrapper.find('[data-workflow-run="workflowId"');

Expand Down
18 changes: 4 additions & 14 deletions client/src/components/Workflow/InvocationsList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,7 @@
</div>
</template>
<template v-slot:cell(history_id)="data">
<div
v-b-tooltip.hover.top.html
:title="`<b>Switch to</b><br>${getHistoryNameById(data.item.history_id)}`"
class="truncate">
<b-link id="switch-to-history" href="#" @click.stop="switchHistory(data.item.history_id)">
{{ getHistoryNameById(data.item.history_id) }}
</b-link>
</div>
<SwitchToHistoryLink :history-id="data.value" />
</template>
<template v-slot:cell(create_time)="data">
<UtcDate :date="data.value" mode="elapsed" />
Expand All @@ -90,7 +83,6 @@
</template>

<script>
import { getGalaxyInstance } from "app";
import HelpText from "components/Help/HelpText";
import { invocationsProvider } from "components/providers/InvocationsProvider";
import UtcDate from "components/UtcDate";
Expand All @@ -103,13 +95,15 @@ import { useWorkflowStore } from "@/stores/workflowStore";
import paginationMixin from "./paginationMixin";

import WorkflowRunButton from "./WorkflowRunButton.vue";
import SwitchToHistoryLink from "@/components/History/SwitchToHistoryLink.vue";

export default {
components: {
HelpText,
UtcDate,
WorkflowInvocationState,
WorkflowRunButton,
HelpText,
SwitchToHistoryLink,
},
mixins: [paginationMixin],
props: {
Expand Down Expand Up @@ -226,10 +220,6 @@ export default {
invocationLink(item) {
return `/workflows/invocations/${item.id}`;
},
switchHistory(historyId) {
const Galaxy = getGalaxyInstance();
Galaxy.currHistoryPanel.switchToHistory(historyId);
},
},
};
</script>
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/webapps/galaxy/services/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ def _data(
# If stats were requested, return them.
if "stats" in kwargs:
if stats["data"]["max"] == 0:
return DataResult(dataset_type=indexer.dataset_type, data=None)
return DataResult(dataset_type=indexer.dataset_type, data=[])
else:
return stats

Expand Down