-
Daniel Göbel authored
#55
Daniel Göbel authored#55
ListWorkflowsView.vue 5.93 KiB
<script setup lang="ts">
import { computed, onMounted, reactive } from "vue";
import type { WorkflowOut } from "@/client/workflow";
import WorkflowCard from "@/components/workflows/WorkflowCard.vue";
import CardTransitionGroup from "@/components/transitions/CardTransitionGroup.vue";
import dayjs from "dayjs";
import FontAwesomeIcon from "@/components/FontAwesomeIcon.vue";
import { WorkflowService } from "@/client/workflow";
import { environment } from "@/environment";
import ArbitraryWorkflowModal from "@/components/workflows/modals/ArbitraryWorkflowModal.vue";
const workflowsState = reactive<{
loading: boolean;
filterString: string;
sortByAttribute: string;
sortDesc: boolean;
workflows: WorkflowOut[];
}>({
loading: true,
filterString: "",
sortByAttribute: "name",
sortDesc: true,
workflows: [],
});
const filterFunctionMapping: Record<
string,
(a: WorkflowOut, b: WorkflowOut) => boolean
> = {
name: (a: WorkflowOut, b: WorkflowOut) =>
workflowsState.sortDesc ? a.name > b.name : a.name < b.name,
release: (a: WorkflowOut, b: WorkflowOut) => {
const a_date = dayjs(a.versions[a.versions.length - 1].created_at);
const b_date = dayjs(b.versions[b.versions.length - 1].created_at);
return workflowsState.sortDesc
? a_date.isBefore(b_date)
: a_date.isAfter(b_date);
},
};
function filterWorkflowByString(workflow: WorkflowOut): boolean {
return workflowsState.filterString.length > 0
? workflow.name.includes(workflowsState.filterString)
: true;
}
function filterWorkflowWithoutVersion(workflow: WorkflowOut): boolean {
return workflow.versions.length > 0;
}
const processedWorkflows = computed<WorkflowOut[]>(() => {
return [
...workflowsState.workflows.filter(
(workflow) =>
filterWorkflowByString(workflow) &&
filterWorkflowWithoutVersion(workflow)
),
].sort((a, b) =>
filterFunctionMapping[workflowsState.sortByAttribute](a, b) ? 1 : -1
);
});
function fetchWorkflows() {
WorkflowService.workflowListWorkflows()
.then((workflows) => {
workflowsState.workflows = workflows;
})
.finally(() => {
workflowsState.loading = false;
});
}
onMounted(() => {
fetchWorkflows();
});
</script>
<template>
<div class="row m-2 border-bottom mb-4">
<h1 class="mb-2">Workflows</h1>
</div>
<div class="d-flex m-2 mb-3 align-items-center justify-content-between">
<div class="col-5 me-auto">
<div class="input-group rounded shadow-sm">
<span class="input-group-text" id="workflows-search-wrapping"
><font-awesome-icon icon="fa-solid fa-magnifying-glass"
/></span>
<input
type="text"
class="form-control"
placeholder="Filter Workflows"
aria-label="Filter Workflows"
aria-describedby="workflows-search-wrapping"
:disabled="workflowsState.loading"
v-model.trim="workflowsState.filterString"
maxlength="20"
/>
</div>
</div>
<span class="fs-5 me-3 text-shadow">Sort By</span>
<div
class="btn-group btn-group-sm w-fit shadow-sm"
role="group"
aria-label="Basic radio toggle button group"
>
<input
type="radio"
class="btn-check"
name="btnradio"
id="sortName"
autocomplete="off"
checked
v-model="workflowsState.sortByAttribute"
value="name"
/>
<label class="btn btn-outline-secondary" for="sortName"
>Alphabetical</label
>
<input
type="radio"
class="btn-check"
name="btnradio"
id="sortLatestRelease"
autocomplete="off"
v-model="workflowsState.sortByAttribute"
value="release"
/>
<label class="btn btn-outline-secondary" for="sortLatestRelease"
>Latest Release</label
>
</div>
<font-awesome-icon
:icon="
workflowsState.sortDesc
? 'fa-solid fa-arrow-down-wide-short'
: 'fa-solid fa-arrow-up-wide-short'
"
@click="workflowsState.sortDesc = !workflowsState.sortDesc"
class="fs-5 ms-3 cursor-pointer"
/>
</div>
<div v-if="environment.DEV_SYSTEM" class="d-grid gap-2 col-4 mx-auto">
<button
class="btn btn-success btn-lg fs-3"
role="button"
data-bs-toggle="modal"
data-bs-target="#arbitraryWorkflowModal"
>
Arbitrary Workflow
</button>
<arbitrary-workflow-modal modal-i-d="arbitraryWorkflowModal" />
</div>
<div v-if="!workflowsState.loading">
<div
v-if="workflowsState.workflows.length === 0"
class="text-center fs-2 mt-5"
>
<font-awesome-icon
icon="fa-solid fa-x"
class="my-5 fs-0"
style="color: var(--bs-secondary)"
/>
<p>There are no workflows in the system. Please come again later.</p>
</div>
<div
v-else-if="processedWorkflows.length === 0"
class="text-center fs-2 mt-5"
>
<font-awesome-icon
icon="fa-solid fa-magnifying-glass"
class="my-5 fs-0"
style="color: var(--bs-secondary)"
/>
<p>
Could not find any Workflows containing<br />'{{
workflowsState.filterString
}}'
</p>
</div>
<CardTransitionGroup
v-else
class="d-flex flex-wrap align-items-center justify-content-between"
>
<workflow-card
v-for="workflow in processedWorkflows"
:key="workflow.workflow_id"
:workflow="workflow"
:loading="false"
/>
</CardTransitionGroup>
</div>
<div
v-else
class="d-flex flex-wrap align-items-center justify-content-between"
>
<workflow-card
v-for="workflow in 4"
:key="workflow"
:workflow="{
name: '',
short_description: '',
repository_url: '',
workflow_id: '',
versions: [],
developer_id: '',
}"
loading
/>
</div>
</template>
<style scoped>
.text-shadow {
text-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
}
</style>