Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions client/src/api/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,17 @@ export async function deleteJob(jobId: string, message?: string): Promise<boolea

return data;
}

/**
* Fetch running jobs
* @returns List of running jobs
*/
export async function fetchJobs(){
const { data, error } = await GalaxyApi().GET("/api/jobs");
Comment on lines +70 to +71

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will list every job independent of the state, so it is better to use pagination here; for that, you can use the limit and offset parameters. You can get inspiration, for example, from the InvocationsScrollList component.

Another important issue here is that, in the case of an admin user, this will list all users' jobs by default, which is definitely not something you want 😅, so even if it is not necessary for regular users, we should pass the current user_id to the endpoint to ensure admins only see their own jobs here.


if (error) {
rethrowSimple(error);
}

return data;
}
2 changes: 2 additions & 0 deletions client/src/components/ActivityBar/ActivityBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import AdminPanel from "@/components/admin/AdminPanel.vue";
import FlexPanel from "@/components/Panels/FlexPanel.vue";
import HistoryGraphPanel from "@/components/Panels/HistoryGraphPanel.vue";
import InteractiveToolsPanel from "@/components/Panels/InteractiveToolsPanel.vue";
import JobPanel from "@/components/Panels/JobPanel.vue";
import MultiviewPanel from "@/components/Panels/MultiviewPanel.vue";
import NotificationsPanel from "@/components/Panels/NotificationsPanel.vue";
import SettingsPanel from "@/components/Panels/SettingsPanel.vue";
Expand Down Expand Up @@ -483,6 +484,7 @@ defineExpose({
<HistoryGraphPanel v-else-if="isActiveSideBar('historygraph')" />
<ChatHistoryPanel v-else-if="isActiveSideBar('galaxyai')" />
<NotificationsPanel v-else-if="isActiveSideBar('notifications')" />
<JobPanel v-else-if="isActiveSideBar('jobs')" in-panel />
<UserToolPanel v-if="isActiveSideBar('user-defined-tools')" in-panel />
<InteractiveToolsPanel v-else-if="isActiveSideBar('interactivetools')" />
<SettingsPanel
Expand Down
67 changes: 67 additions & 0 deletions client/src/components/Panels/JobPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script setup lang="ts">
import { faHdd, faWrench } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { computed } from "vue";
import { useRouter } from "vue-router/composables";

import type { JobBaseModel } from "@/api/jobs.js";
import { useHistoryStore } from "@/stores/historyStore.js";
import { useJobStore } from "@/stores/jobStore.js";

import GCard from "../Common/GCard.vue";
import JobState from "../JobStates/JobState.vue";
import ActivityPanel from "@/components/Panels/ActivityPanel.vue";

const jobsStore = useJobStore();
jobsStore.fetchAllJobs();

const filteredJobs = computed(() => {
return jobsStore.allJobs.filter((job) => job.tool_id != "__DATA_FETCH__")
})

const router = useRouter();

function historyName(historyId: string) {
const historyStore = useHistoryStore();
return historyStore.getHistoryNameById(historyId);
}

function cardClicked(job: JobBaseModel) {
// if (props.inPanel) {
// emit("invocation-clicked");
// }
router.push(`/jobs/${job.id}/view`);
}

</script>

<template>
<ActivityPanel
title="Running jobs"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title "Running Jobs" is a bit misleading, since this is showing all jobs regardless of their status.

go-to-all-title="Open Jobs List"
href="/workflows/jobs">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this /workflows/jobs is a hallucination 😅 and will display a blank page since it is not implemented. Also, it should probably be just jobs/; the word workflows here could be misleading.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During the training we wanted to display the job panel from a workflow invocation. This explains why we ended using this path.
I think this worked on my local Galaxy instance otherwise I would not have pushed it… but maybe I’m wrong, GCC training was so short!
Thanks for your comments 😊

<GCard
v-for="job in filteredJobs"
:key="job.id"
clickable
:title="job.tool_id"
:title-icon="{icon: faWrench}"
:update-time="job.update_time"
@click="() => cardClicked(job)"
>
<template v-slot:description>
<Heading class="m-0" size="text">
<FontAwesomeIcon :icon="faHdd" fixed-width />

<small v-if="job.history_id" class="text-muted truncate-n-lines two-lines">
{{ historyName(job.history_id) }}
</small>
</Heading>
</template>
<template v-slot:badges>
<JobState :job="job" />
</template>
</GCard>
</ActivityPanel>

</template>
17 changes: 15 additions & 2 deletions client/src/stores/activitySetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
faPlay,
faSitemap,
faTable,
faTrain,
faUpload,
faWrench,
} from "@fortawesome/free-solid-svg-icons";
faWrench} from "@fortawesome/free-solid-svg-icons";

import { ACTIVITY_LABELS } from "@/components/Page/constants";
import type { Activity } from "@/stores/activityStoreTypes";
Expand Down Expand Up @@ -93,6 +93,19 @@ export const defaultActivities = [
tooltip: "Search and run workflows",
visible: true,
},
{
anonymous: false,
description: "Displays all job runs.",
icon: faTrain,
id: "jobs",
mutable: false,
optional: false,
panel: true,
title: "Jobs",
to: null,
tooltip: "Show all job runs",
visible: true,
},
{
anonymous: false,
description: "Displays all workflow runs.",
Expand Down
10 changes: 9 additions & 1 deletion client/src/stores/jobStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import { defineStore } from "pinia";
import { ref } from "vue";

import { GalaxyApi } from "@/api";
import { type ResponseVal, type ShowFullJobResponse, TERMINAL_STATES } from "@/api/jobs";
import { fetchJobs, type JobBaseModel, type ResponseVal, type ShowFullJobResponse, TERMINAL_STATES } from "@/api/jobs";
import { type FetchParams, useKeyedCache } from "@/composables/keyedCache";
import { rethrowSimpleWithStatus } from "@/utils/simple-error";

export const useJobStore = defineStore("jobStore", () => {
const latestResponse = ref<ResponseVal | null>(null);
const allJobs = ref<JobBaseModel[]>([]);

async function fetchAllJobs(){
allJobs.value = await fetchJobs();
}

async function fetchJobById(params: FetchParams): Promise<ShowFullJobResponse> {
const { data, error, response } = await GalaxyApi().GET("/api/jobs/{job_id}", {
Expand Down Expand Up @@ -57,6 +62,8 @@ export const useJobStore = defineStore("jobStore", () => {

return {
fetchJob,
fetchAllJobs,
allJobs,
saveLatestResponse,
getJob,
getJobLoadError,
Expand All @@ -65,3 +72,4 @@ export const useJobStore = defineStore("jobStore", () => {
pollJobUntilTerminal,
};
});

Loading