Loading client/src/components/Common/GCard.vue +13 −1 Original line number Diff line number Diff line Loading @@ -176,6 +176,11 @@ interface Props { * @default "Last updated" */ updateTimeTitle?: string; /** Whether this card is highlighted (for example, as a range selection anchor) * @default false */ highlighted?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading Loading @@ -207,6 +212,7 @@ const props = withDefaults(defineProps<Props>(), { updateTime: "", updateTimeIcon: () => faEdit, updateTimeTitle: "Last updated", highlighted: false, }); /** Loading Loading @@ -283,8 +289,10 @@ const allowedTitleLines = computed(() => props.titleNLines); function onKeyDown(event: KeyboardEvent) { if ((props.clickable && event.key === "Enter") || event.key === " ") { event.stopPropagation(); emit("click", event); } else if (props.clickable) { event.stopPropagation(); emit("keydown", event); } } Loading @@ -310,7 +318,7 @@ function onKeyDown(event: KeyboardEvent) { <div :id="`g-card-content-${props.id}`" class="g-card-content d-flex flex-column justify-content-between h-100 p-2" :class="contentClass"> :class="[{ 'g-card-highlighted': props.highlighted }, contentClass]"> <slot> <div class="d-flex flex-column flex-gapy-1"> <div Loading Loading @@ -708,6 +716,10 @@ function onKeyDown(event: KeyboardEvent) { border-left: 0.25rem solid $brand-primary; } &.g-card-highlighted .g-card-content { box-shadow: 0 0 0 0.2rem transparentize($brand-primary, 0.75); } &.g-card-clickable { cursor: pointer; Loading client/src/components/History/HistoryCard.vue +46 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,20 @@ interface Props { * @default false */ sharedView?: boolean; /** * Whether the card is clickable for keyboard navigation * @type {boolean} * @default false */ clickable?: boolean; /** * Whether this card is highlighted (for example, as a range selection anchor) * @type {boolean} * @default false */ highlighted?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading @@ -102,6 +116,8 @@ const props = withDefaults(defineProps<Props>(), { selectable: false, selected: false, sharedView: false, clickable: false, highlighted: false, }); const router = useRouter(); Loading Loading @@ -144,6 +160,18 @@ const emit = defineEmits<{ * @event updateFilter */ (e: "updateFilter", key: string, value: any): void; /** * Emitted when a keyboard event occurs on the history card * @event on-key-down */ (e: "on-key-down", history: AnyHistoryEntry, event: KeyboardEvent): void; /** * Emitted when the history card is clicked * @event on-history-card-click */ (e: "on-history-card-click", history: AnyHistoryEntry, event: Event): void; }>(); /** Loading Loading @@ -203,12 +231,25 @@ async function onTagsUpdate(historyId: string, tags: string[]) { await historyStore.updateHistory(historyId, { tags: tags }); emit("refreshList", true, true); } function onClick(event: Event) { if (props.clickable) { emit("on-history-card-click", props.history, event); } } function onKeyDown(event: KeyboardEvent) { if (props.clickable) { emit("on-key-down", props.history, event); } } </script> <template> <GCard :id="`history-${history.id}`" :key="history.id" class="history-card" :title="historyCardTitle" :title-badges="historyCardTitleBadges" :title-n-lines="2" Loading @@ -226,11 +267,15 @@ async function onTagsUpdate(historyId: string, tags: string[]) { :tags-editable="userOwnsHistory(currentUser, history)" :max-visible-tags="props.gridView ? 2 : 8" :update-time="history.update_time" :clickable="props.clickable" :highlighted="props.highlighted" @titleClick="onTitleClick" @rename="() => router.push(`/histories/rename?id=${history.id}`)" @select="isMyHistory(history) && emit('select', history)" @tagsUpdate="(tags) => onTagsUpdate(history.id, tags)" @tagClick="(tag) => emit('tagClick', tag)"> @tagClick="(tag) => emit('tagClick', tag)" @click="onClick" @keydown="onKeyDown"> <template v-if="props.archivedView && isArchivedHistory(history)" v-slot:titleActions> <ExportRecordDOILink :export-record-uri="history.export_record_data?.target_uri" /> </template> Loading client/src/components/History/HistoryCardList.vue +48 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ * @tagClick="onTagClick" /> */ import type { Ref } from "vue"; import type { AnyHistoryEntry, MyHistory } from "@/api/histories"; import { isMyHistory } from "@/api/histories"; Loading Loading @@ -76,6 +78,26 @@ interface Props { * @default [] */ selectedHistoryIds?: { id: string }[]; /** * Whether cards are clickable for navigation * @type {boolean} * @default false */ clickable?: boolean; /** * Item refs for keyboard navigation * @type {Record<string, Ref<InstanceType<typeof HistoryCard> | null>>} * @default {} */ itemRefs?: Record<string, Ref<InstanceType<typeof HistoryCard> | null>>; /** * Range select anchor for keyboard navigation * @type {AnyHistoryEntry | undefined} */ rangeSelectAnchor?: AnyHistoryEntry; } const props = withDefaults(defineProps<Props>(), { Loading @@ -83,6 +105,9 @@ const props = withDefaults(defineProps<Props>(), { publishedView: false, selectable: false, selectedHistoryIds: () => [], clickable: false, itemRefs: () => ({}), rangeSelectAnchor: undefined, }); /** Loading Loading @@ -112,14 +137,28 @@ const emit = defineEmits<{ * @event updateFilter */ (e: "updateFilter", key: string, value: any): void; /** * Emitted when a keyboard event occurs on a history card * @event on-key-down */ (e: "on-key-down", history: AnyHistoryEntry, event: KeyboardEvent): void; /** * Emitted when a history card is clicked * @event on-history-card-click */ (e: "on-history-card-click", history: AnyHistoryEntry, event: Event): void; }>(); </script> <template> <div class="history-card-list d-flex flex-wrap overflow-auto"> <div class="history-card-list d-flex flex-wrap overflow-auto pt-1"> <HistoryCard v-for="history in props.histories" :ref="props.itemRefs[history.id]" :key="history.id" tabindex="0" :history="history" :grid-view="props.gridView" :shared-view="props.sharedView" Loading @@ -127,14 +166,21 @@ const emit = defineEmits<{ :archived-view="props.archivedView" :selectable="props.selectable" :selected="props.selectedHistoryIds.some((selected) => selected.id === history.id)" :clickable="props.clickable" :highlighted="props.rangeSelectAnchor?.id === history.id" class="history-card-in-list" @select="isMyHistory(history) && emit('select', history)" @tagClick="(...args) => emit('tagClick', ...args)" @refreshList="(...args) => emit('refreshList', ...args)" @updateFilter="(...args) => emit('updateFilter', ...args)" /> @updateFilter="(...args) => emit('updateFilter', ...args)" @on-key-down="(...args) => emit('on-key-down', ...args)" @on-history-card-click="(...args) => emit('on-history-card-click', ...args)" /> </div> </template> <style lang="scss" scoped> @import "theme/blue.scss"; .history-card-list { container: cards-list / inline-size; } Loading client/src/components/History/HistoryList.vue +59 −26 Original line number Diff line number Diff line Loading @@ -32,7 +32,10 @@ import { getPublishedHistories, getSharedHistories, } from "@/api/histories"; import type HistoryCard from "@/components/History/HistoryCard.vue"; import { useHistoryCardActions } from "@/components/History/useHistoryCardActions"; import { useConfirmDialog } from "@/composables/confirmDialog"; import { useSelectedItems } from "@/composables/selectedItems/selectedItems"; import { Toast } from "@/composables/toast"; import { useHistoryStore } from "@/stores/historyStore"; import { updateHistoryFields } from "@/stores/services/history.services"; Loading Loading @@ -98,7 +101,6 @@ const bulkTagsLoading = ref(false); const bulkDeleteOrRestoreLoading = ref(false); const bulkPurgeLoading = ref(false); const historiesLoaded = ref<AnyHistoryEntry[]>([]); const selectedHistories = ref<SelectedHistory[]>([]); /** Computed property that determines if the current view is "My Histories" */ const myView = computed(() => props.activeList === "my"); Loading Loading @@ -150,6 +152,49 @@ const invalidFilters = computed(() => historyListFilters.value.getValidFilters(r const isSurroundedByQuotes = computed(() => /^["'].*["']$/.test(filterText.value)); const hasInvalidFilters = computed(() => !isSurroundedByQuotes.value && Object.keys(invalidFilters.value).length > 0); const selectedHistories = computed<SelectedHistory[]>(() => { const ids = Array.from(selectedItems.value.keys()); const matchingHistories = historiesLoaded.value.filter((h) => ids.includes(h.id)); return matchingHistories.map((h) => ({ id: h.id, name: h.name, published: h.published, purged: h.purged, })); }); const { selectedItems, selectAllInCurrentQuery, isSelected, setSelected, resetSelection, itemRefs, initSelectedItem, onClick, onKeyDown, } = useSelectedItems<AnyHistoryEntry, typeof HistoryCard>({ scopeKey: computed(() => `${props.activeList}-histories-${filterText.value}`), getItemKey: (item) => item.id, filterText: filterText, totalItemsInQuery: computed(() => totalHistories.value ?? 0), allItems: historiesLoaded, filterClass: historyListFilters.value, selectable: computed(() => myView.value), onDelete: async (item) => { const { onDeleteHistory } = useHistoryCardActions( computed(() => item), false, () => load(true), ); await onDeleteHistory(); }, expectedKeyDownClass: "history-card", getAttributeForRangeSelection(item) { return `g-card-${item.id}`; }, }); /** * Updates a specific filter value in the current filter text * @param {string} filterKey - The key of the filter to update Loading Loading @@ -252,16 +297,10 @@ function validatedFilterText(): string { /** * Toggles selection of a specific history item * @param {SelectedHistory} h - The history object to toggle selection for * @param {AnyHistoryEntry} h - The history object to toggle selection for */ function onSelectHistory(h: SelectedHistory) { const index = selectedHistories.value.findIndex((selected) => selected.id === h.id); if (index === -1) { selectedHistories.value.push(h); } else { selectedHistories.value.splice(index, 1); } function onSelectHistory(h: AnyHistoryEntry) { setSelected(h, !isSelected(h)); } /** Loading @@ -270,14 +309,9 @@ function onSelectHistory(h: SelectedHistory) { */ function onSelectAllHistories() { if (selectedHistories.value.length === historiesLoaded.value.length) { selectedHistories.value = []; resetSelection(); } else { selectedHistories.value = historiesLoaded.value.map((h) => ({ id: h.id, name: h.name, published: h.published, purged: h.purged, })); selectAllInCurrentQuery(); } } Loading Loading @@ -326,15 +360,13 @@ async function onBulkDeleteOrPurge(purge: boolean = false) { Toast.success(`${purge ? "Purged" : "Deleted"} ${totalSelected} histories.`); selectedHistories.value = []; resetSelection(); } catch (e) { Toast.error(`Failed to ${purge ? "purge" : "delete"} some histories.`); } finally { bulkPurgeLoading.value = false; bulkDeleteOrRestoreLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading Loading @@ -374,14 +406,12 @@ async function onBulkRestore() { Toast.success(`Restored ${totalSelected} histories.`); selectedHistories.value = []; resetSelection(); } catch (e) { Toast.error(`Failed to restore some histories.`); } finally { bulkDeleteOrRestoreLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading Loading @@ -423,8 +453,6 @@ async function onBulkTagsAdd(tags: string[]) { } finally { bulkTagsLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading @@ -436,7 +464,7 @@ async function onBulkTagsAdd(tags: string[]) { watch([filterText, sortBy, sortDesc], async () => { offset.value = 0; selectedHistories.value = []; resetSelection(); await load(true); }); Loading Loading @@ -597,8 +625,13 @@ onMounted(async () => { :grid-view="currentListViewMode === 'grid'" :selectable="myView" :selected-history-ids="selectedHistories" :item-refs="itemRefs" :range-select-anchor="initSelectedItem" :clickable="true" @refreshList="load" @select="onSelectHistory" @on-key-down="onKeyDown" @on-history-card-click="onClick" @updateFilter="updateFilterValue" @tagClick="(tag) => updateFilterValue('tag', `'${tag}'`)" /> </BOverlay> Loading client/src/components/History/useHistoryCardActions.ts +2 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ export function useHistoryCardActions( historyCardExtraActions: CardAction[]; historyCardSecondaryActions: CardAction[]; historyCardPrimaryActions: ComputedRef<CardAction[]>; onDeleteHistory: (purge?: boolean) => Promise<void>; } { const { confirm } = useConfirmDialog(); Loading Loading @@ -296,5 +297,5 @@ export function useHistoryCardActions( ]; }); return { historyCardExtraActions, historyCardSecondaryActions, historyCardPrimaryActions }; return { historyCardExtraActions, historyCardSecondaryActions, historyCardPrimaryActions, onDeleteHistory }; } Loading
client/src/components/Common/GCard.vue +13 −1 Original line number Diff line number Diff line Loading @@ -176,6 +176,11 @@ interface Props { * @default "Last updated" */ updateTimeTitle?: string; /** Whether this card is highlighted (for example, as a range selection anchor) * @default false */ highlighted?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading Loading @@ -207,6 +212,7 @@ const props = withDefaults(defineProps<Props>(), { updateTime: "", updateTimeIcon: () => faEdit, updateTimeTitle: "Last updated", highlighted: false, }); /** Loading Loading @@ -283,8 +289,10 @@ const allowedTitleLines = computed(() => props.titleNLines); function onKeyDown(event: KeyboardEvent) { if ((props.clickable && event.key === "Enter") || event.key === " ") { event.stopPropagation(); emit("click", event); } else if (props.clickable) { event.stopPropagation(); emit("keydown", event); } } Loading @@ -310,7 +318,7 @@ function onKeyDown(event: KeyboardEvent) { <div :id="`g-card-content-${props.id}`" class="g-card-content d-flex flex-column justify-content-between h-100 p-2" :class="contentClass"> :class="[{ 'g-card-highlighted': props.highlighted }, contentClass]"> <slot> <div class="d-flex flex-column flex-gapy-1"> <div Loading Loading @@ -708,6 +716,10 @@ function onKeyDown(event: KeyboardEvent) { border-left: 0.25rem solid $brand-primary; } &.g-card-highlighted .g-card-content { box-shadow: 0 0 0 0.2rem transparentize($brand-primary, 0.75); } &.g-card-clickable { cursor: pointer; Loading
client/src/components/History/HistoryCard.vue +46 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,20 @@ interface Props { * @default false */ sharedView?: boolean; /** * Whether the card is clickable for keyboard navigation * @type {boolean} * @default false */ clickable?: boolean; /** * Whether this card is highlighted (for example, as a range selection anchor) * @type {boolean} * @default false */ highlighted?: boolean; } const props = withDefaults(defineProps<Props>(), { Loading @@ -102,6 +116,8 @@ const props = withDefaults(defineProps<Props>(), { selectable: false, selected: false, sharedView: false, clickable: false, highlighted: false, }); const router = useRouter(); Loading Loading @@ -144,6 +160,18 @@ const emit = defineEmits<{ * @event updateFilter */ (e: "updateFilter", key: string, value: any): void; /** * Emitted when a keyboard event occurs on the history card * @event on-key-down */ (e: "on-key-down", history: AnyHistoryEntry, event: KeyboardEvent): void; /** * Emitted when the history card is clicked * @event on-history-card-click */ (e: "on-history-card-click", history: AnyHistoryEntry, event: Event): void; }>(); /** Loading Loading @@ -203,12 +231,25 @@ async function onTagsUpdate(historyId: string, tags: string[]) { await historyStore.updateHistory(historyId, { tags: tags }); emit("refreshList", true, true); } function onClick(event: Event) { if (props.clickable) { emit("on-history-card-click", props.history, event); } } function onKeyDown(event: KeyboardEvent) { if (props.clickable) { emit("on-key-down", props.history, event); } } </script> <template> <GCard :id="`history-${history.id}`" :key="history.id" class="history-card" :title="historyCardTitle" :title-badges="historyCardTitleBadges" :title-n-lines="2" Loading @@ -226,11 +267,15 @@ async function onTagsUpdate(historyId: string, tags: string[]) { :tags-editable="userOwnsHistory(currentUser, history)" :max-visible-tags="props.gridView ? 2 : 8" :update-time="history.update_time" :clickable="props.clickable" :highlighted="props.highlighted" @titleClick="onTitleClick" @rename="() => router.push(`/histories/rename?id=${history.id}`)" @select="isMyHistory(history) && emit('select', history)" @tagsUpdate="(tags) => onTagsUpdate(history.id, tags)" @tagClick="(tag) => emit('tagClick', tag)"> @tagClick="(tag) => emit('tagClick', tag)" @click="onClick" @keydown="onKeyDown"> <template v-if="props.archivedView && isArchivedHistory(history)" v-slot:titleActions> <ExportRecordDOILink :export-record-uri="history.export_record_data?.target_uri" /> </template> Loading
client/src/components/History/HistoryCardList.vue +48 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ * @tagClick="onTagClick" /> */ import type { Ref } from "vue"; import type { AnyHistoryEntry, MyHistory } from "@/api/histories"; import { isMyHistory } from "@/api/histories"; Loading Loading @@ -76,6 +78,26 @@ interface Props { * @default [] */ selectedHistoryIds?: { id: string }[]; /** * Whether cards are clickable for navigation * @type {boolean} * @default false */ clickable?: boolean; /** * Item refs for keyboard navigation * @type {Record<string, Ref<InstanceType<typeof HistoryCard> | null>>} * @default {} */ itemRefs?: Record<string, Ref<InstanceType<typeof HistoryCard> | null>>; /** * Range select anchor for keyboard navigation * @type {AnyHistoryEntry | undefined} */ rangeSelectAnchor?: AnyHistoryEntry; } const props = withDefaults(defineProps<Props>(), { Loading @@ -83,6 +105,9 @@ const props = withDefaults(defineProps<Props>(), { publishedView: false, selectable: false, selectedHistoryIds: () => [], clickable: false, itemRefs: () => ({}), rangeSelectAnchor: undefined, }); /** Loading Loading @@ -112,14 +137,28 @@ const emit = defineEmits<{ * @event updateFilter */ (e: "updateFilter", key: string, value: any): void; /** * Emitted when a keyboard event occurs on a history card * @event on-key-down */ (e: "on-key-down", history: AnyHistoryEntry, event: KeyboardEvent): void; /** * Emitted when a history card is clicked * @event on-history-card-click */ (e: "on-history-card-click", history: AnyHistoryEntry, event: Event): void; }>(); </script> <template> <div class="history-card-list d-flex flex-wrap overflow-auto"> <div class="history-card-list d-flex flex-wrap overflow-auto pt-1"> <HistoryCard v-for="history in props.histories" :ref="props.itemRefs[history.id]" :key="history.id" tabindex="0" :history="history" :grid-view="props.gridView" :shared-view="props.sharedView" Loading @@ -127,14 +166,21 @@ const emit = defineEmits<{ :archived-view="props.archivedView" :selectable="props.selectable" :selected="props.selectedHistoryIds.some((selected) => selected.id === history.id)" :clickable="props.clickable" :highlighted="props.rangeSelectAnchor?.id === history.id" class="history-card-in-list" @select="isMyHistory(history) && emit('select', history)" @tagClick="(...args) => emit('tagClick', ...args)" @refreshList="(...args) => emit('refreshList', ...args)" @updateFilter="(...args) => emit('updateFilter', ...args)" /> @updateFilter="(...args) => emit('updateFilter', ...args)" @on-key-down="(...args) => emit('on-key-down', ...args)" @on-history-card-click="(...args) => emit('on-history-card-click', ...args)" /> </div> </template> <style lang="scss" scoped> @import "theme/blue.scss"; .history-card-list { container: cards-list / inline-size; } Loading
client/src/components/History/HistoryList.vue +59 −26 Original line number Diff line number Diff line Loading @@ -32,7 +32,10 @@ import { getPublishedHistories, getSharedHistories, } from "@/api/histories"; import type HistoryCard from "@/components/History/HistoryCard.vue"; import { useHistoryCardActions } from "@/components/History/useHistoryCardActions"; import { useConfirmDialog } from "@/composables/confirmDialog"; import { useSelectedItems } from "@/composables/selectedItems/selectedItems"; import { Toast } from "@/composables/toast"; import { useHistoryStore } from "@/stores/historyStore"; import { updateHistoryFields } from "@/stores/services/history.services"; Loading Loading @@ -98,7 +101,6 @@ const bulkTagsLoading = ref(false); const bulkDeleteOrRestoreLoading = ref(false); const bulkPurgeLoading = ref(false); const historiesLoaded = ref<AnyHistoryEntry[]>([]); const selectedHistories = ref<SelectedHistory[]>([]); /** Computed property that determines if the current view is "My Histories" */ const myView = computed(() => props.activeList === "my"); Loading Loading @@ -150,6 +152,49 @@ const invalidFilters = computed(() => historyListFilters.value.getValidFilters(r const isSurroundedByQuotes = computed(() => /^["'].*["']$/.test(filterText.value)); const hasInvalidFilters = computed(() => !isSurroundedByQuotes.value && Object.keys(invalidFilters.value).length > 0); const selectedHistories = computed<SelectedHistory[]>(() => { const ids = Array.from(selectedItems.value.keys()); const matchingHistories = historiesLoaded.value.filter((h) => ids.includes(h.id)); return matchingHistories.map((h) => ({ id: h.id, name: h.name, published: h.published, purged: h.purged, })); }); const { selectedItems, selectAllInCurrentQuery, isSelected, setSelected, resetSelection, itemRefs, initSelectedItem, onClick, onKeyDown, } = useSelectedItems<AnyHistoryEntry, typeof HistoryCard>({ scopeKey: computed(() => `${props.activeList}-histories-${filterText.value}`), getItemKey: (item) => item.id, filterText: filterText, totalItemsInQuery: computed(() => totalHistories.value ?? 0), allItems: historiesLoaded, filterClass: historyListFilters.value, selectable: computed(() => myView.value), onDelete: async (item) => { const { onDeleteHistory } = useHistoryCardActions( computed(() => item), false, () => load(true), ); await onDeleteHistory(); }, expectedKeyDownClass: "history-card", getAttributeForRangeSelection(item) { return `g-card-${item.id}`; }, }); /** * Updates a specific filter value in the current filter text * @param {string} filterKey - The key of the filter to update Loading Loading @@ -252,16 +297,10 @@ function validatedFilterText(): string { /** * Toggles selection of a specific history item * @param {SelectedHistory} h - The history object to toggle selection for * @param {AnyHistoryEntry} h - The history object to toggle selection for */ function onSelectHistory(h: SelectedHistory) { const index = selectedHistories.value.findIndex((selected) => selected.id === h.id); if (index === -1) { selectedHistories.value.push(h); } else { selectedHistories.value.splice(index, 1); } function onSelectHistory(h: AnyHistoryEntry) { setSelected(h, !isSelected(h)); } /** Loading @@ -270,14 +309,9 @@ function onSelectHistory(h: SelectedHistory) { */ function onSelectAllHistories() { if (selectedHistories.value.length === historiesLoaded.value.length) { selectedHistories.value = []; resetSelection(); } else { selectedHistories.value = historiesLoaded.value.map((h) => ({ id: h.id, name: h.name, published: h.published, purged: h.purged, })); selectAllInCurrentQuery(); } } Loading Loading @@ -326,15 +360,13 @@ async function onBulkDeleteOrPurge(purge: boolean = false) { Toast.success(`${purge ? "Purged" : "Deleted"} ${totalSelected} histories.`); selectedHistories.value = []; resetSelection(); } catch (e) { Toast.error(`Failed to ${purge ? "purge" : "delete"} some histories.`); } finally { bulkPurgeLoading.value = false; bulkDeleteOrRestoreLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading Loading @@ -374,14 +406,12 @@ async function onBulkRestore() { Toast.success(`Restored ${totalSelected} histories.`); selectedHistories.value = []; resetSelection(); } catch (e) { Toast.error(`Failed to restore some histories.`); } finally { bulkDeleteOrRestoreLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading Loading @@ -423,8 +453,6 @@ async function onBulkTagsAdd(tags: string[]) { } finally { bulkTagsLoading.value = false; selectedHistories.value = tmpSelected; await load(true); } } Loading @@ -436,7 +464,7 @@ async function onBulkTagsAdd(tags: string[]) { watch([filterText, sortBy, sortDesc], async () => { offset.value = 0; selectedHistories.value = []; resetSelection(); await load(true); }); Loading Loading @@ -597,8 +625,13 @@ onMounted(async () => { :grid-view="currentListViewMode === 'grid'" :selectable="myView" :selected-history-ids="selectedHistories" :item-refs="itemRefs" :range-select-anchor="initSelectedItem" :clickable="true" @refreshList="load" @select="onSelectHistory" @on-key-down="onKeyDown" @on-history-card-click="onClick" @updateFilter="updateFilterValue" @tagClick="(tag) => updateFilterValue('tag', `'${tag}'`)" /> </BOverlay> Loading
client/src/components/History/useHistoryCardActions.ts +2 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ export function useHistoryCardActions( historyCardExtraActions: CardAction[]; historyCardSecondaryActions: CardAction[]; historyCardPrimaryActions: ComputedRef<CardAction[]>; onDeleteHistory: (purge?: boolean) => Promise<void>; } { const { confirm } = useConfirmDialog(); Loading Loading @@ -296,5 +297,5 @@ export function useHistoryCardActions( ]; }); return { historyCardExtraActions, historyCardSecondaryActions, historyCardPrimaryActions }; return { historyCardExtraActions, historyCardSecondaryActions, historyCardPrimaryActions, onDeleteHistory }; }