diff --git a/client/src/components/SelectionDialog/SelectionDialog.vue b/client/src/components/SelectionDialog/SelectionDialog.vue index 7db32b262d2..943b7fb43c6 100644 --- a/client/src/components/SelectionDialog/SelectionDialog.vue +++ b/client/src/components/SelectionDialog/SelectionDialog.vue @@ -3,29 +3,30 @@ import type { IconDefinition } from "@fortawesome/fontawesome-svg-core"; import { faCheckSquare, faMinusSquare, faSquare } from "@fortawesome/free-regular-svg-icons"; import { faCaretLeft, faCheck, faFolder, faSpinner, faTimes } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; -import { BAlert, BButton, BLink, BPagination, BTable } from "bootstrap-vue"; +import { BAlert, BButton, BLink, BPagination, BSpinner } from "bootstrap-vue"; import { computed, ref, watch } from "vue"; +import type { RowClickEvent, TableField } from "@/components/Common/GTable.types"; import { type ItemsProvider, SELECTION_STATES, type SelectionState } from "@/components/SelectionDialog/selectionTypes"; import type Filtering from "@/utils/filtering"; -import type { FieldEntry, SelectionItem } from "./selectionTypes"; +import type { SelectionItem } from "./selectionTypes"; import GModal from "../BaseComponents/GModal.vue"; import Heading from "../Common/Heading.vue"; import FilterMenu from "@/components/Common/FilterMenu.vue"; -import LoadingSpan from "@/components/LoadingSpan.vue"; +import GTable from "@/components/Common/GTable.vue"; import DataDialogSearch from "@/components/SelectionDialog/DataDialogSearch.vue"; import StatelessTags from "@/components/TagsMultiselect/StatelessTags.vue"; -const LABEL_FIELD: FieldEntry = { key: "label", sortable: true }; -const SELECT_ICON_FIELD: FieldEntry = { key: "__select_icon__", label: "", sortable: false }; +const LABEL_FIELD: TableField = { key: "label", label: "Name", sortable: true }; +const SELECT_ICON_FIELD: TableField = { key: "__select_icon__", label: "", sortable: false }; interface Props { disableOk?: boolean; errorMessage?: string; fileMode?: boolean; - fields?: FieldEntry[]; + fields?: TableField[]; isBusy?: boolean; isEncoded?: boolean; items?: SelectionItem[]; @@ -87,15 +88,22 @@ const currentPage = ref(1); const perPage = ref(25); const showAdvancedSearch = ref(false); +const providerRequestId = ref(0); +const providerItems = ref([]); +const sortBy = ref(undefined); +const sortDesc = ref(undefined); + +const usingProvider = computed(() => Boolean(props.itemsProvider)); + const okButtonText = computed(() => { return props.okButtonText ? props.okButtonText : props.fileMode ? "Select" : "Select this folder"; }); -const fieldDetails = computed(() => { - const fields = props.fields.slice().map((x) => { - x.sortable = x.sortable === undefined ? true : x.sortable; - return x; - }); +const fieldDetails = computed(() => { + const fields: TableField[] = props.fields.slice().map((field) => ({ + ...field, + sortable: field.sortable ?? true, + })); if (fields.length === 0) { fields.unshift(LABEL_FIELD); } @@ -105,7 +113,44 @@ const fieldDetails = computed(() => { return fields; }); -function selectionIcon(variant: string) { +const tableItems = computed(() => { + return usingProvider.value ? providerItems.value : props.items; +}); + +async function loadProviderItems() { + if (!props.itemsProvider || !props.optionsShow) { + return; + } + + const requestId = ++providerRequestId.value; + const result = await props.itemsProvider({ + apiUrl: props.providerUrl, + currentPage: currentPage.value, + perPage: perPage.value, + filter: filter.value || undefined, + sortBy: sortBy.value, + sortDesc: sortDesc.value, + }); + + if (requestId === providerRequestId.value) { + providerItems.value = result ?? []; + } +} + +function onSortChanged(newSortBy: string, newSortDesc: boolean) { + sortBy.value = newSortBy || undefined; + sortDesc.value = newSortDesc; +} + +function onRowClick(event: RowClickEvent) { + emit("onClick", event.item); +} + +function onOpen(item: SelectionItem) { + emit("onOpen", item); +} + +function selectionIcon(variant?: string) { switch (variant) { case SELECTION_STATES.SELECTED: return faCheckSquare; @@ -116,13 +161,6 @@ function selectionIcon(variant: string) { } } -/** Resets pagination when a filter/search word is entered **/ -function filtered(items: SelectionItem[]) { - if (props.itemsProvider === undefined) { - resetPagination(); - } -} - /** Format time stamp */ function formatTime(value: string) { if (value) { @@ -159,6 +197,30 @@ if (props.watchOnPageChanges) { } const dialog = ref | null>(null); + +watch( + [ + () => props.itemsProvider, + currentPage, + perPage, + filter, + sortBy, + sortDesc, + () => props.providerUrl, + () => props.optionsShow, + ], + () => { + if (props.itemsProvider && props.optionsShow) { + void loadProviderItems(); + } + }, + { immediate: true }, +); + +watch(filter, () => { + resetPagination(); +}); + watch( () => dialog.value, (newValue) => { @@ -208,19 +270,21 @@ defineExpose({
- + @sort-changed="onSortChanged" + @row-click="onRowClick"> + + + + + + - + +
- + + +
- No search results found for: {{ filter }}. + No search results found for: {{ filter }} .
No entries.