diff --git a/client/src/components/Panels/Upload/UploadMethodList.vue b/client/src/components/Panels/Upload/UploadMethodList.vue index 008e2c4c327..2f40bbb495e 100644 --- a/client/src/components/Panels/Upload/UploadMethodList.vue +++ b/client/src/components/Panels/Upload/UploadMethodList.vue @@ -2,7 +2,9 @@ import { computed, ref } from "vue"; import { useRouter } from "vue-router/composables"; +import type { CardBadge } from "@/components/Common/GCard.types"; import { useConfig } from "@/composables/config"; +import { useUploadStagingCounts } from "@/composables/upload/useUploadStaging"; import type { UploadMethodConfig } from "./types"; import { useAllUploadMethods } from "./uploadMethodRegistry"; @@ -30,6 +32,7 @@ const query = ref(""); const searchInputClass = computed(() => (props.searchTeleportTarget ? "my-2" : props.inPanel ? "my-2" : "mb-3")); const allUploadMethods = useAllUploadMethods(); +const stagedCountsByMode = useUploadStagingCounts(); const availableMethods = computed(() => { if (!isConfigLoaded.value) { @@ -64,6 +67,23 @@ function selectUploadMethod(method: UploadMethodConfig) { function updateQuery(newQuery: string) { query.value = newQuery; } + +function getStagingBadges(method: UploadMethodConfig): CardBadge[] { + const count = stagedCountsByMode.value[method.id] ?? 0; + if (count === 0) { + return []; + } + return [ + { + id: `staged-${method.id}`, + label: String(count), + title: `${count} upload item${count === 1 ? "" : "s"} staged and pending submission`, + variant: "primary", + type: "badge", + handler: () => selectUploadMethod(method), + }, + ]; +} diff --git a/client/src/composables/upload/useUploadStaging.ts b/client/src/composables/upload/useUploadStaging.ts index c14dab0bd60..eebf4bb4c67 100644 --- a/client/src/composables/upload/useUploadStaging.ts +++ b/client/src/composables/upload/useUploadStaging.ts @@ -1,7 +1,10 @@ -import { onMounted, type Ref, watch } from "vue"; +import { storeToRefs } from "pinia"; +import { computed, onMounted, type Ref, watch } from "vue"; import type { UploadMethod } from "@/components/Panels/Upload/types"; -import { type StagedUploadItem, useUploadStagingStore } from "@/stores/uploadStagingStore"; +import type { PasteContentItem } from "@/components/Panels/Upload/types/uploadItem"; +import type { StagedUploadItem } from "@/stores/uploadStagingStore"; +import { useUploadStagingStore } from "@/stores/uploadStagingStore"; interface UseUploadStagingReturn { clear: () => void; @@ -46,3 +49,31 @@ export function useUploadStaging( clear, }; } + +export function useUploadStagingCounts() { + const { itemsByMode } = storeToRefs(useUploadStagingStore()); + + return computed>>(() => { + const counts: Partial> = {}; + for (const [mode, items] of Object.entries(itemsByMode.value)) { + const uploadMode = mode as UploadMethod; + counts[uploadMode] = countStagedItems(uploadMode, items ?? []); + } + return counts; + }); +} + +function countStagedItems(mode: UploadMethod, items: StagedUploadItem[]): number { + if (mode == "paste-content") { + return items.filter(isNonEmptyPasteContentItem).length; + } + return items.length; +} + +function isNonEmptyPasteContentItem(item: StagedUploadItem): item is PasteContentItem { + return isPasteContentItem(item) && item.content.trim().length > 0; +} + +export function isPasteContentItem(item: StagedUploadItem): item is PasteContentItem { + return "content" in item; +} diff --git a/client/src/stores/uploadStagingStore.ts b/client/src/stores/uploadStagingStore.ts index 23634159788..f670619d49a 100644 --- a/client/src/stores/uploadStagingStore.ts +++ b/client/src/stores/uploadStagingStore.ts @@ -27,12 +27,19 @@ export const useUploadStagingStore = defineStore("uploadStagingStore", () => { } function setItems(mode: UploadMethod, items: T[]) { - // always store a new array reference so reactivity triggers + // Ensure the key exists (Vue 2 key reactivity) with a one-time object replacement. + if (!(mode in itemsByMode.value)) { + itemsByMode.value = { ...itemsByMode.value, [mode]: [] }; + } + // Always store a new array reference so reactivity triggers. itemsByMode.value[mode] = [...items]; } function clearItems(mode: UploadMethod) { - delete itemsByMode.value[mode]; + if (!(mode in itemsByMode.value)) { + return; + } + itemsByMode.value[mode] = []; } return {