dashboard/new-dashboard/src/components/common/BranchSelect.vue (227 lines of code) (raw):

<template> <MultiSelect v-model="branchValue" title="Branch" :loading="branchConfigurator.state.loading" :disabled="branchConfigurator.state.disabled" :options="branchItems" :placeholder="placeholder" option-label="label" option-value="value" :show-toggle-all="false" panel-class="w-fit" panel-style="overflow: visible" :selection-limit="selectionLimit" :filter="hasManyElements" @hide="clearSubMenu" > <template #value="slotProps"> <div class="group flex items-center gap-1"> <div class="w-4 h-4"> <BranchIcon /> </div> <span v-if="!slotProps.value || slotProps.value.length === 0"> {{ placeholder }} </span> <span v-if="slotProps.value && slotProps.value.length === 1"> {{ slotProps.value[0] }} </span> <span v-if="slotProps.value && slotProps.value.length > 1"> {{ branchesSelectLabelFormat(slotProps.value) }} </span> <ChevronDownIcon class="-mr-1 ml-1 h-5 w-5 shrink-0" aria-hidden="true" /> </div> </template> <template #footer> <div class="border-t border-solid border-neutral-200 relative"> <ul class="p-multiselect-items p-component"> <li v-if="versionItems !== undefined && versionItems.length > 0" class="p-multiselect-option flex items-center gap-2" @click="openVersionSubmenu" > <span class="flex items-center gap-1 overflow-hidden"> Version type <span v-if="versionValue !== null && versionValue.length > 0" class="truncate" > {{ versionValue?.length < 2 ? versionValue[0] : `Selected ${versionValue?.length}` }} </span> </span> <span class="pi pi-angle-right ml-[auto]" /> </li> <li v-if="triggeredItems.length > 0" class="p-multiselect-option flex items-center gap-2" @click="openTriggeredSubmenu" > <span class="flex items-center gap-1 overflow-hidden"> Triggered by <span v-if="triggeredValueFiltered !== null && triggeredValueFiltered !== undefined && triggeredValueFiltered.length > 0" class="truncate" > {{ triggeredValueFiltered?.length < 2 ? triggeredValueFiltered[0] : `Selected ${triggeredValueFiltered?.length}` }} </span> </span> <span class="pi pi-angle-right ml-[auto]" /> </li> </ul> <div v-if="activeSubMenu === SubMenu.VERSION_TYPE && versionItems.length > 0" class="absolute p-multiselect-overlay p-component w-[270px] max-h-[200px] branch-select-dropdown" style="left: 100%" > <ul class="p-multiselect-list"> <li v-for="item in versionItems" :key="item.label" > <div class="flex items-center p-multiselect-option p-component"> <Checkbox v-model="versionValue" :value="item.value" :input-id="item.value" class="field-checkbox" /> <label class="w-full inline-block" :for="item.value" > <span>{{ item.label }}</span> </label> </div> </li> </ul> </div> <div v-if="activeSubMenu === SubMenu.TRIGGERED_BY && triggeredItems.length > 0" class="absolute p-multiselect-overlay p-component w-[270px] max-h-[200px] branch-select-dropdown" style="left: 100%" > <ul class="p-multiselect-items p-component"> <div v-if="triggeredItems.length === 0">No available options</div> <li v-for="item in triggeredItems" :key="item.label" > <div class="flex items-center p-multiselect-option p-component"> <Checkbox v-model="triggeredValue" :value="item.value" :input-id="item.value" class="field-checkbox" /> <label class="w-full inline-block" :for="item.value" > <span>{{ item.label }}</span> </label> </div> </li> </ul> </div> </div> </template> <template #dropdownicon> <span class="hidden" /> </template> </MultiSelect> </template> <script setup lang="ts"> import { ChevronDownIcon } from "@heroicons/vue/20/solid" import { computed, ref, toValue } from "vue" import { sortBranches } from "../../configurators/BranchConfigurator" import { DimensionConfigurator } from "../../configurators/DimensionConfigurator" import { branchesSelectLabelFormat } from "../../shared/labels" import { usePlaceholder } from "../charts/placeholder" import BranchIcon from "./BranchIcon.vue" interface Props { branchConfigurator: DimensionConfigurator releaseConfigurator?: DimensionConfigurator triggeredByConfigurator?: DimensionConfigurator selectionLimit?: number } const enum SubMenu { TRIGGERED_BY, VERSION_TYPE, } const triggeredValueFiltered = computed(() => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition return triggeredValue.value?.filter((it) => it !== null) }) const activeSubMenu = ref<SubMenu | null>(null) const openVersionSubmenu = () => { activeSubMenu.value = SubMenu.VERSION_TYPE } const openTriggeredSubmenu = () => { activeSubMenu.value = SubMenu.TRIGGERED_BY } const clearSubMenu = () => { activeSubMenu.value = null } const { branchConfigurator, releaseConfigurator = undefined, triggeredByConfigurator = undefined, selectionLimit = undefined } = defineProps<Props>() function createItems(configurator?: DimensionConfigurator) { return computed(() => { if (configurator == undefined) { return [] } const values = (toValue(configurator.values) as string[]).sort((a, b) => { if (toValue(configurator.selected)?.includes(b)) return 1 if (toValue(configurator.selected)?.includes(a)) return -1 return sortBranches(a, b) }) return values.map((it) => { return { label: it, value: it } }) }) } function createValueFrom(configurator?: DimensionConfigurator) { return computed<string[] | null>({ get() { if (configurator == null) { return null } const values = toValue(configurator.values) if (values.length === 0) { return null } const value = configurator.selected.value if (Array.isArray(value)) { return value } return value == null || value === "" ? [] : [value] }, set(value) { if (configurator == null) return configurator.selected.value = value == null || value.length === 0 ? null : value }, }) } const branchValue = createValueFrom(branchConfigurator) const versionValue = createValueFrom(releaseConfigurator) const triggeredValue = createValueFrom(triggeredByConfigurator) const branchItems = createItems(branchConfigurator) const versionItems = createItems(releaseConfigurator) const triggeredItems = createItems(triggeredByConfigurator) const placeholder = usePlaceholder( { label: "Branch" }, () => branchConfigurator.values.value, () => branchConfigurator.selected.value ) const hasManyElements = computed(() => { return branchItems.value.length > 4 }) </script> <style> .branch-select-dropdown { top: 0; margin-top: 0; border-top-left-radius: 0; } </style>