From 5b17ae74d3e75f050eb32fed4185d7558130cfe7 Mon Sep 17 00:00:00 2001 From: Efren Lim Date: Tue, 31 Mar 2026 15:44:08 +0800 Subject: [PATCH 1/4] fix: added the missing delete collection on the collections details page Signed-off-by: Efren Lim --- .../collection/components/details/header.vue | 76 ++++++++++++++++- .../shared/components/collection-card.vue | 2 +- .../confirm/components/confirm-global.vue | 29 +++++++ .../confirm/components/confirm-modal.vue | 85 +++++++++++++++++++ .../modules/confirm/store/confirm.store.ts | 53 ++++++++++++ frontend/app/layouts/default.vue | 2 + 6 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 frontend/app/components/shared/modules/confirm/components/confirm-global.vue create mode 100644 frontend/app/components/shared/modules/confirm/components/confirm-modal.vue create mode 100644 frontend/app/components/shared/modules/confirm/store/confirm.store.ts diff --git a/frontend/app/components/modules/collection/components/details/header.vue b/frontend/app/components/modules/collection/components/details/header.vue index e1ed84b5..c96bab90 100644 --- a/frontend/app/components/modules/collection/components/details/header.vue +++ b/frontend/app/components/modules/collection/components/details/header.vue @@ -145,6 +145,29 @@ SPDX-License-Identifier: MIT Share + + + + + + Delete + + @@ -216,18 +239,34 @@ SPDX-License-Identifier: MIT + + + +
+ +

Deleting collection...

+
+
+ + diff --git a/frontend/app/components/shared/modules/confirm/components/confirm-modal.vue b/frontend/app/components/shared/modules/confirm/components/confirm-modal.vue new file mode 100644 index 00000000..0b220a9d --- /dev/null +++ b/frontend/app/components/shared/modules/confirm/components/confirm-modal.vue @@ -0,0 +1,85 @@ + + + + + + diff --git a/frontend/app/components/shared/modules/confirm/store/confirm.store.ts b/frontend/app/components/shared/modules/confirm/store/confirm.store.ts new file mode 100644 index 00000000..eae51463 --- /dev/null +++ b/frontend/app/components/shared/modules/confirm/store/confirm.store.ts @@ -0,0 +1,53 @@ +// Copyright (c) 2025 The Linux Foundation and each contributor. +// SPDX-License-Identifier: MIT +import { defineStore } from 'pinia'; +import { ref } from 'vue'; + +export interface ConfirmOptions { + title?: string; + message: string; + confirmLabel?: string; + cancelLabel?: string; +} + +const defaultOptions: ConfirmOptions = { + title: 'Confirm', + message: '', + confirmLabel: 'Ok', + cancelLabel: 'Cancel', +}; + +export const useConfirmStore = defineStore('confirm', () => { + const isConfirmModalOpen = ref(false); + const confirmOptions = ref(defaultOptions); + const resolvePromise = ref<((value: boolean) => void) | null>(null); + + const openConfirmModal = (options: ConfirmOptions): Promise => { + confirmOptions.value = { ...defaultOptions, ...options }; + isConfirmModalOpen.value = true; + + return new Promise((resolve) => { + resolvePromise.value = resolve; + }); + }; + + const confirm = () => { + isConfirmModalOpen.value = false; + resolvePromise.value?.(true); + resolvePromise.value = null; + }; + + const cancel = () => { + isConfirmModalOpen.value = false; + resolvePromise.value?.(false); + resolvePromise.value = null; + }; + + return { + isConfirmModalOpen, + confirmOptions, + openConfirmModal, + confirm, + cancel, + }; +}); diff --git a/frontend/app/layouts/default.vue b/frontend/app/layouts/default.vue index 0b880845..93eaa33f 100644 --- a/frontend/app/layouts/default.vue +++ b/frontend/app/layouts/default.vue @@ -18,6 +18,7 @@ SPDX-License-Identifier: MIT + @@ -35,6 +36,7 @@ import LfEditCollectionGlobal from '~/components/modules/collection/components/e import LfDuplicateCollectionGlobal from '~/components/modules/collection/components/create-modal/duplicate-collection-global.vue'; import LfxCopilotGlobal from '~/components/shared/modules/copilot/components/copilot-global.vue'; import LfxCommunityFilterGlobal from '~/components/modules/project/components/community/sections/community-filter-global.vue'; +import LfxConfirmGlobal from '~/components/shared/modules/confirm/components/confirm-global.vue'; import { useRichSchema } from '~~/composables/useRichSchema'; import { useBannerStore } from '~/components/shared/store/banner.store'; From abc2ee68bb5af1add013d60dd15e94f803b8c58b Mon Sep 17 00:00:00 2001 From: Efren Lim Date: Wed, 1 Apr 2026 13:23:50 +0800 Subject: [PATCH 2/4] chore: added collection type enum Signed-off-by: Efren Lim --- .../collection/components/details/header.vue | 6 ++-- .../config/collection-type-config.ts | 16 +++++++--- .../services/collections.api.service.ts | 32 ++++++++++++------- .../collection/views/collection-details.vue | 5 +-- .../collection/views/collection-list.vue | 13 +++++--- .../shared/components/collection-card.vue | 15 +++++---- .../components/collection-list-item.vue | 7 ++-- .../shared/components/like-button.vue | 5 +-- 8 files changed, 60 insertions(+), 39 deletions(-) diff --git a/frontend/app/components/modules/collection/components/details/header.vue b/frontend/app/components/modules/collection/components/details/header.vue index c96bab90..1660269e 100644 --- a/frontend/app/components/modules/collection/components/details/header.vue +++ b/frontend/app/components/modules/collection/components/details/header.vue @@ -121,7 +121,7 @@ SPDX-License-Identifier: MIT /> { route: LfxRoutes.COLLECTIONS_CURATED, activeClass: '!bg-neutral-200', iconHighlightClass: '!bg-neutral-900', - type: 'curated', + type: CollectionTypeEnum.CURATED, description: 'Hand-picked collections from The Linux Foundation.', }, ]; @@ -32,7 +38,7 @@ export const collectionTabs = (user: User | null): CollectionTypesTabs[] => { route: LfxRoutes.COLLECTIONS_COMMUNITY, activeClass: '!bg-accent-200', iconHighlightClass: '!bg-accent-500', - type: 'community', + type: CollectionTypeEnum.COMMUNITY, description: 'Discover collections from the open source community.', }); @@ -44,7 +50,7 @@ export const collectionTabs = (user: User | null): CollectionTypesTabs[] => { route: LfxRoutes.COLLECTIONS_MY_COLLECTIONS, activeClass: '!bg-discovery-200', iconHighlightClass: '!bg-discovery-500', - type: 'my-collections', + type: CollectionTypeEnum.MY_COLLECTIONS, description: "Collections you've created or liked.", }); } @@ -55,13 +61,13 @@ export const collectionTabs = (user: User | null): CollectionTypesTabs[] => { // This only applies to the collection details page header export const headerBackground = (type?: CollectionType, curatedColor?: string | null) => { switch (type) { - case 'curated': + case CollectionTypeEnum.CURATED: return { background: curatedColor ? `linear-gradient(0deg, ${curatedColor}00, ${curatedColor}0D), var(--White, #FFF)` : 'linear-gradient(0deg, #0F172B00, #0F172B0D), var(--White, #FFF)', }; - case 'community': + case CollectionTypeEnum.COMMUNITY: return { background: 'linear-gradient(0deg, #009AFF00, #009AFF0D), var(--White, #FFF)', }; diff --git a/frontend/app/components/modules/collection/services/collections.api.service.ts b/frontend/app/components/modules/collection/services/collections.api.service.ts index 00716d82..922d1c73 100644 --- a/frontend/app/components/modules/collection/services/collections.api.service.ts +++ b/frontend/app/components/modules/collection/services/collections.api.service.ts @@ -15,6 +15,7 @@ import type { ProjectInsights } from '~~/types/project'; import { TanstackKey } from '~/components/shared/types/tanstack'; import type { SearchProject, SearchResults } from '~~/types/search'; import { type User } from '~~/types/auth/auth-user.types'; +import { CollectionTypeEnum } from '~/components/modules/collection/config/collection-type-config'; export interface CategoryGroupOptions { value: string; @@ -220,10 +221,10 @@ class CollectionsApiService { } fetchDiscoveryCuratedCollections() { - const params = this.discoveryParams('curated'); + const params = this.discoveryParams(CollectionTypeEnum.CURATED); const queryKey = computed(() => [ TanstackKey.COLLECTION_DISCOVERY, - 'curated', + CollectionTypeEnum.CURATED, params.sort, params.pageSize, params.type, @@ -238,10 +239,10 @@ class CollectionsApiService { } fetchDiscoveryCommunityCollections() { - const params = this.discoveryParams('community'); + const params = this.discoveryParams(CollectionTypeEnum.COMMUNITY); const queryKey = computed(() => [ TanstackKey.COLLECTION_DISCOVERY, - 'community', + CollectionTypeEnum.COMMUNITY, params.sort, params.pageSize, params.type, @@ -256,10 +257,10 @@ class CollectionsApiService { } fetchDiscoveryMyCollections(user: User | null) { - const params = this.discoveryParams('my-collections'); + const params = this.discoveryParams(CollectionTypeEnum.MY_COLLECTIONS); const queryKey = computed(() => [ TanstackKey.COLLECTION_DISCOVERY, - 'my', + CollectionTypeEnum.MY_COLLECTIONS, params.sort, params.pageSize, params.type, @@ -277,14 +278,21 @@ class CollectionsApiService { async prefetchDiscoveryCollections() { const queryClient = useQueryClient(); - const curatedQueryKey = [TanstackKey.COLLECTION_DISCOVERY, 'curated']; - const communityQueryKey = [TanstackKey.COLLECTION_DISCOVERY, 'community']; - const myCollectionsQueryKey = [TanstackKey.COLLECTION_DISCOVERY, 'my']; + const curatedQueryKey = [TanstackKey.COLLECTION_DISCOVERY, CollectionTypeEnum.CURATED]; + const communityQueryKey = [TanstackKey.COLLECTION_DISCOVERY, CollectionTypeEnum.COMMUNITY]; + const myCollectionsQueryKey = [ + TanstackKey.COLLECTION_DISCOVERY, + CollectionTypeEnum.MY_COLLECTIONS, + ]; - const curatedQueryFn = this.fetchCollectionsQueryFn(() => this.discoveryParams('curated')); - const communityQueryFn = this.fetchCollectionsQueryFn(() => this.discoveryParams('community')); + const curatedQueryFn = this.fetchCollectionsQueryFn(() => + this.discoveryParams(CollectionTypeEnum.CURATED), + ); + const communityQueryFn = this.fetchCollectionsQueryFn(() => + this.discoveryParams(CollectionTypeEnum.COMMUNITY), + ); const myCollectionsQueryFn = this.fetchMyCollectionsQueryFn(() => - this.discoveryParams('my-collections'), + this.discoveryParams(CollectionTypeEnum.MY_COLLECTIONS), ); await Promise.all([ diff --git a/frontend/app/components/modules/collection/views/collection-details.vue b/frontend/app/components/modules/collection/views/collection-details.vue index 9b84d264..18964c5b 100644 --- a/frontend/app/components/modules/collection/views/collection-details.vue +++ b/frontend/app/components/modules/collection/views/collection-details.vue @@ -114,6 +114,7 @@ import type { Project } from '~~/types/project'; import { useAuthStore } from '~/components/modules/auth/store/auth.store'; import { TanstackKey } from '~/components/shared/types/tanstack'; import { useLikeCounts } from '~/components/modules/collection/composables/useLikeCounts'; +import { CollectionTypeEnum } from '~/components/modules/collection/config/collection-type-config'; const props = defineProps<{ slug: string; @@ -152,10 +153,10 @@ const { queryParams } = useQueryParam(collectionDetailsParamsGetter, collectionL const { onlyLFProjects, collectionSort } = queryParams.value; const collectionType = computed(() => { if (user.value && user.value.sub === currentCollection.value?.ssoUserId) { - return 'my-collections'; + return CollectionTypeEnum.MY_COLLECTIONS; } - return currentCollection.value?.ssoUserId ? 'community' : 'curated'; + return currentCollection.value?.ssoUserId ? CollectionTypeEnum.COMMUNITY : CollectionTypeEnum.CURATED; }); const sort = ref(collectionSort || 'contributorCount_desc'); diff --git a/frontend/app/components/modules/collection/views/collection-list.vue b/frontend/app/components/modules/collection/views/collection-list.vue index 232f3182..c8dd5dc9 100644 --- a/frontend/app/components/modules/collection/views/collection-list.vue +++ b/frontend/app/components/modules/collection/views/collection-list.vue @@ -33,7 +33,7 @@ SPDX-License-Identifier: MIT v-for="collection in flatData" :key="collection.slug" :collection="collection" - :show-like-count="props.type !== 'my-collections'" + :show-like-count="props.type !== CollectionTypeEnum.MY_COLLECTIONS" :variant="props.type" @updated="refreshList" /> @@ -91,7 +91,7 @@ SPDX-License-Identifier: MIT
@@ -124,6 +124,7 @@ import { useBannerStore } from '~/components/shared/store/banner.store'; import { useAuthStore } from '~/components/modules/auth/store/auth.store'; import { useCollectionsStore } from '~/components/modules/collection/store/collections.store'; import { useLikeCounts } from '~/components/modules/collection/composables/useLikeCounts'; +import { CollectionTypeEnum } from '~/components/modules/collection/config/collection-type-config'; const props = defineProps<{ type?: CollectionType; @@ -146,11 +147,11 @@ const params = computed(() => ({ pageSize: pageSize.value, sort: sort.value || 'starred_desc', categories: undefined, - type: props.type === 'my-collections' ? undefined : props.type, + type: props.type === CollectionTypeEnum.MY_COLLECTIONS ? undefined : props.type, })); const { data, isPending, isFetchingNextPage, fetchNextPage, hasNextPage, isSuccess, error, refetch } = - props.type === 'my-collections' + props.type === CollectionTypeEnum.MY_COLLECTIONS ? COLLECTIONS_API_SERVICE.fetchMyCollections(params, user) : COLLECTIONS_API_SERVICE.fetchCollections(params); @@ -161,7 +162,9 @@ const flatData = computed(() => ), ); -const collectionIds = computed(() => (props.type !== 'my-collections' ? flatData.value.map((c) => c.id) : [])); +const collectionIds = computed(() => + props.type !== CollectionTypeEnum.MY_COLLECTIONS ? flatData.value.map((c) => c.id) : [], +); useLikeCounts(collectionIds); const classDisplay = computed(() => { diff --git a/frontend/app/components/shared/components/collection-card.vue b/frontend/app/components/shared/components/collection-card.vue index 016e9b18..33b86a40 100644 --- a/frontend/app/components/shared/components/collection-card.vue +++ b/frontend/app/components/shared/components/collection-card.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: MIT
@@ -28,7 +28,7 @@ SPDX-License-Identifier: MIT /> -