<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 FontAwesomeIcon from "@/components/FontAwesomeIcon.vue"; import { environment } from "@/environment"; import ArbitraryWorkflowModal from "@/components/workflows/modals/ArbitraryWorkflowModal.vue"; import { useWorkflowStore } from "@/stores/workflows"; const workflowRepository = useWorkflowStore(); const workflowsState = reactive<{ loading: boolean; filterString: string; sortByAttribute: string; sortDesc: boolean; }>({ loading: true, filterString: "", sortByAttribute: "name", sortDesc: true, }); const filterFunctionMapping: Record< string, (a: WorkflowOut, b: WorkflowOut) => boolean > = { name: (a: WorkflowOut, b: WorkflowOut) => workflowsState.sortDesc ? a.name.toLowerCase() > b.name.toLowerCase() : a.name.toLowerCase() < b.name.toLowerCase(), release: (a: WorkflowOut, b: WorkflowOut) => { return workflowsState.sortDesc ? a.versions[0].created_at <= b.versions[0].created_at : a.versions[0].created_at > b.versions[0].created_at; }, }; 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 workflowWithSortedVersions = computed<WorkflowOut[]>(() => { const temp = JSON.parse(JSON.stringify(workflowRepository.workflows)); for (const index in temp) { const versions = [...temp[index].versions]; versions.sort((a, b) => (a.created_at < b.created_at ? 1 : -1)); temp[index].versions = versions; } return temp; }); const processedWorkflows = computed<WorkflowOut[]>(() => { const temp = workflowWithSortedVersions.value.filter( (workflow) => filterWorkflowByString(workflow) && filterWorkflowWithoutVersion(workflow), ); temp.sort((a, b) => filterFunctionMapping[workflowsState.sortByAttribute](a, b) ? 1 : -1, ); return temp; }); onMounted(() => { workflowRepository.fetchWorkflows(() => { workflowsState.loading = false; }); }); </script> <template> <div class="row m-2 border-bottom mb-4"> <h2 class="mb-2">Select Workflow</h2> </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" id="filterWorkflowInput" 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 Workflows 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" > Test my Workflow </button> <arbitrary-workflow-modal modal-id="arbitraryWorkflowModal" /> </div> <div v-if="!workflowsState.loading"> <div v-if="workflowRepository.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: '', private: false, }" loading /> </div> </template> <style scoped> .text-shadow { text-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } </style>